library("tidyverse")
library("ggplot2")
library(plyr)
library("mco")
run_1 = read_csv('/Users/b1017579/Documents/PhD/Projects/10-ELECSIM/run/validation-optimisation/data/run_2.csv')
Missing column names filled in: 'X1' [1]Parsed with column specification:
cols(
  X1 = col_double(),
  id = col_double(),
  run_number = col_double(),
  time_taken = col_double(),
  timestamp_start = col_double(),
  timestamp_end = col_double(),
  reward = col_double(),
  individual_m = col_double(),
  individual_c = col_double(),
  coal = col_double(),
  nuclear = col_double(),
  ccgt = col_double(),
  wind = col_double(),
  solar = col_double()
)
tail(run_1)
ggplot(filter(run_1), aes(y=individual_m, x=individual_c)) + geom_hex(bins=10)

p = ggplot(run_1, aes(y=individual_m, x=individual_c, color=reward), size=10) + facet_wrap(~run_number) + geom_point() + ggtitle("Scatter plot of input parameters and reward")
p$labels$fill <- "Absolute \nPercentage \nError"
print(p)

p = ggplot(run_1, aes(y=individual_m, x=individual_c, color=reward), size=10) + facet_wrap(~run_number) + geom_jitter() + ggtitle("Scatter (jitter) plot of input parameters and reward")
p$labels$fill <- "Absolute \nPercentage \nError"
print(p)

p = ggplot(run_1, aes(y=individual_m, x=individual_c, color=time_taken), size=10) + facet_wrap(~run_number) + geom_jitter() + ggtitle("Scatter plot of input parameters and time taken")
p$labels$fill <- "Time \nTaken"
print(p)

p=ggplot(run_1, aes(y=individual_m, x=individual_c)) + stat_summary_hex(aes(z = reward), bins=10) + facet_wrap(~ run_number) + scale_x_continuous(breaks = round(seq(min(run_1$individual_c), max(run_1$individual_c), by = 25),1)) + ggtitle("Hexagonal heatmap of input parameters and Absolute Percentage Error")
p$labels$fill <- "Absolute \nPercentage \nError"
print(p)
ggsave("~/Desktop/genetic_algorithm_progression.png")
Saving 6.89 x 4.26 in image

run_1 %>% dplyr::group_by(run_number) %>% dplyr::summarise(avg_reward = mean(reward)) %>% ggplot()+ geom_smooth(data=run_1, aes(x=run_number, reward))+geom_line(aes(x=run_number, y=avg_reward))+ggtitle("Average reward vs Population Number") 

# accurate_area = filter(run_1, individual_c<-4.8, individual_c>-50, individual_m <0.003, individual_m > 0.0023)
# accurate_area = filter(run_1, reward < 0.2)
# accurate_area = filter(run_1, run_number==11)
accurate_area = filter(run_1, run_number == 16)
accurate_area
 ggplot(data=accurate_area, aes(x=individual_c, y=individual_m, color=reward))+geom_jitter()+geom_point(color="red", alpha=0.5) + ggtitle("Scatter and Jitterplot of Reward against Input Parameters for \nLast Population of GA")

accurate_area_long = gather(accurate_area, "key", "value", "coal", "ccgt", "wind", "nuclear", "solar")
accurate_area_long_perc = accurate_area_long %>% group_by(id) %>% mutate(value_perc = value/sum(value))
params_more_than_10 = run_1 %>% group_by(individual_c, individual_m) %>% dplyr::mutate(number = n()) %>% ungroup() %>% filter(number> 10) %>% dplyr::mutate_if(is.numeric, round, 6) 
params_more_than_10 %>% ggplot(aes(as.factor(individual_c), reward)) +geom_violin()+facet_wrap(~individual_m)+ theme(axis.text.x = element_text(angle = 90, hjust = 1)) +geom_jitter(position=position_jitter(0.2), alpha=0.05) + ggtitle("Violin plot of input parameters with more than 10 simulations \nagainst distribution of reward")

accurate_area %>% mutate_if(is.numeric, round, 6) %>% ggplot(aes(as.factor(individual_c), reward)) +geom_violin()+facet_wrap(~individual_m)+ theme(axis.text.x = element_text(angle = 90, hjust = 1)) +geom_jitter(position=position_jitter(0.2))+ ggtitle("Violin plot of input parameters with more than 10 simulations of last population of GA\nagainst distribution of reward")

actual_mix = read_csv('/Users/b1017579/Documents/PhD/Projects/10-ELECSIM/elecsim/data/processed/electricity_mix/energy_mix_historical.csv')
Missing column names filled in: 'X1' [1]Parsed with column specification:
cols(
  X1 = col_double(),
  year = col_double(),
  variable = col_character(),
  value = col_double()
)
actual_mix_2018 = filter(actual_mix, year==2018)
actual_mix_2018$type = "actual"
actual_mix_2018
actual_mix_2018_reduced = filter(actual_mix_2018, variable %in% c("ccgt", 'wind', 'nuclear', 'solar', 'coal'))
actual_mix_2018_reduced = actual_mix_2018_reduced %>% mutate(value_perc = value/sum(value))
actual_mix_2018_reduced = dplyr::rename(actual_mix_2018_reduced, key=variable)
head(actual_mix_2018_reduced)
accurate_area_long_perc$type = 'predicted'
accurate_area_long_perc
comparison = rbind(select(ungroup(accurate_area_long_perc), "key", "type", "value", 'value_perc'), select(actual_mix_2018_reduced, -X1, -year))
ggplot(comparison, aes(x=key, y=value_perc, fill=type)) +
  stat_summary(geom = "bar", fun.y = mean, position = "dodge2")+ stat_summary(geom = "errorbar", fun.data = mean_se, position = "dodge2") + ylab("Energy Mix (%)") + ggtitle("Combination of all runs in last genetic algorithm run")
ggsave('~/Desktop/average_error_of_best_params.png')
Saving 6.89 x 4.26 in image

best_result = run_1 %>% group_by("id") %>% filter(reward==min(reward)) %>% gather("key", "value", "coal", "ccgt", "wind", "nuclear", "solar") %>% group_by(id) %>% mutate(value_perc = value/sum(value)) %>% mutate(type="predicted")
comparison_best = rbind(select(ungroup(best_result), "key", "type", "value", 'value_perc'), select(actual_mix_2018_reduced, -X1, -year))
ggplot(comparison_best, aes(x=key, y=value_perc, fill=type)) + geom_col(position = "dodge2") + ylab("Energy Mix (%)") + ggtitle("Best single run")

pdc_example = read_csv('/Users/b1017579/Documents/PhD/Projects/10-ELECSIM/notebooks/validation-optimisation/data/price_demand_curve_example.csv')
Missing column names filled in: 'X1' [1]Parsed with column specification:
cols(
  X1 = col_double(),
  accepted_price = col_double(),
  segment_demand = col_double(),
  segment_hour = col_double()
)
demand_range = data.frame(x=seq(from=min(pdc_example$segment_demand),max(pdc_example$segment_demand),length.out=500))
get_line = function(c, m){
    y = m * demand_range + c
    return(y)
}
get_x = function(){
    return(demand_range)
}
# lines = accurate_area %>% group_by(id) %>% apply(get_line(.))
lines = ddply(accurate_area, .(id), transform, y=get_line(individual_c, individual_m), x=get_x())
ggplot() + geom_line(data=lines, aes(x=x.1, y=x, group=id, color=reward)) + stat_smooth(data=pdc_example, aes(x=segment_demand, y=accepted_price), method="lm", col="red") + geom_point(data=pdc_example, aes(x=segment_demand, y=accepted_price)) + xlab("Demand (MW)") + ylab("Accepted Price") + ggtitle("Last genetic algorithm run price curves between 2023-2028 \ncompared to price in 2018")

best_75_percentile = accurate_area %>% group_by(individual_c, individual_m) %>% dplyr::summarise(number=n(), quantiles = list(enframe(quantile(reward, probs=c(0.25,0.5,0.75))))) %>% unnest %>% ungroup() %>% filter(number>10) %>% group_by(name) %>%filter(rank(value, ties.method="first")==1)
p = ddply(best_75_percentile, .(name), transform, y=get_line(individual_c, individual_m), x=get_x())  %>% ggplot() + geom_line(aes(x=x.1, y=x, color=name))+ stat_smooth(data=pdc_example, aes(x=segment_demand, y=accepted_price), method="lm", col="yellow") + geom_point(data=pdc_example, aes(x=segment_demand, y=accepted_price)) + xlab("Demand (MW)") + ylab("Accepted Price") + ggtitle("Price curve of best runs at different percentiles of last genetic \nalgorithm population")
p$labels$fill <- "Percentiles"
print(p)

best_percentiles_comparison = inner_join(accurate_area, best_75_percentile, by=c('individual_c', 'individual_m')) %>% gather("key", "value", "coal", "ccgt", "wind", "nuclear", "solar") %>% group_by(id) %>% mutate(value_perc = value/sum(value)) %>% mutate(type=name)
comparison_percentiles = rbind(select(ungroup(best_percentiles_comparison), "key", "type", "value", 'value_perc'), select(actual_mix_2018_reduced, -X1, -year))
comparison_percentiles %>% ggplot(aes(x=key, y=value_perc, fill=type)) + stat_summary(geom = "bar", fun.y = mean, position = "dodge2")+ stat_summary(geom = "errorbar", fun.data = mean_se, position = "dodge2") + ggtitle("Comparison of energy mix of final genetic algorithm population \nat different quantile levels")

rbind(filter(select(ungroup(best_percentiles_comparison), "key", "type", "value", 'value_perc'),type=="50%"), select(actual_mix_2018_reduced, -X1, -year)) %>% ggplot(aes(x=key, y=value_perc, fill=type)) + stat_summary(geom = "bar", fun.y = mean, position = "dodge2")+ stat_summary(geom = "errorbar", fun.data = mean_se, position = "dodge2") + ggtitle("Best parameter combinations from final genetic algorithm run")

BEST PARAMETER COMBINATION FROM ALL RUNS

best_75_percentile_all_runs = run_1 %>% group_by(individual_c, individual_m) %>% dplyr::summarise(number=n(), quantiles = list(enframe(quantile(reward, probs=c(0.25,0.5,0.75, 0.9, 1.0))))) %>% unnest %>% ungroup() %>% filter(number>10) %>% group_by(name) %>%filter(rank(value, ties.method="first")==1)
p = ddply(best_75_percentile_all_runs, .(name), transform, y=get_line(individual_c, individual_m), x=get_x())  %>% ggplot() + geom_line(aes(x=x.1, y=x, color=name))+ stat_smooth(data=pdc_example, aes(x=segment_demand, y=accepted_price), method="lm", col="yellow") + geom_point(data=pdc_example, aes(x=segment_demand, y=accepted_price)) + xlab("Demand (MW)") + ylab("Accepted Price") + ggtitle("Percentiles from all runs")
p$labels$fill <- "Percentiles"
print(p)

best_percentiles_comparison = inner_join(run_1, best_75_percentile_all_runs, by=c('individual_c', 'individual_m')) %>% gather("key", "value", "coal", "ccgt", "wind", "nuclear", "solar") %>% group_by(id) %>% mutate(value_perc = value/sum(value)) %>% mutate(type=name)
comparison_percentiles = rbind(select(ungroup(best_percentiles_comparison), "key", "type", "value", 'value_perc'), select(actual_mix_2018_reduced, -X1, -year))
comparison_percentiles %>% ggplot(aes(x=key, y=value_perc, fill=type)) + stat_summary(geom = "bar", fun.y = mean, position = "dodge2")+ stat_summary(geom = "errorbar", fun.data = mean_se, position = "dodge2")

rbind(filter(select(ungroup(best_percentiles_comparison), "key", "type", "value", 'value_perc'),type=="75%" | type=="90%"), select(actual_mix_2018_reduced, -X1, -year)) %>% ggplot(aes(x=key, y=value_perc, fill=type)) + stat_summary(geom = "bar", fun.y = mean, position = "dodge2")+ stat_summary(geom = "errorbar", fun.data = mean_se, position = "dodge2") + ggtitle("Best parameter combinations from all genetic algorithm runs")

Calculation of best quantile to select combination of parameters for lowest reward

best_params = params_more_than_10 %>% group_by(individual_c, individual_m) %>% gather("key", "value", "coal", "ccgt", "wind", "nuclear", "solar") %>% group_by(id) %>% mutate(value_perc = value/sum(value)) %>% group_by(id, key) %>% inner_join(actual_mix_2018_reduced, by="key") %>% mutate(diff_perc = abs(value_perc.x-value_perc.y)) %>% group_by(id) %>% summarise(mean_diff_perc = mean(diff_perc), individual_c = mean(individual_c), individual_m = mean(individual_m)) %>% filter(rank(mean_diff_perc, ties.method="first")==1)
best_params_comparison = filter(run_1,dplyr::near(x=individual_c, y=best_params$individual_c[1], tol=0.00001),dplyr::near(x=individual_m, y=best_params$individual_m[1], tol=0.00001)) %>% gather("key", "value", "coal", "ccgt", "wind", "nuclear", "solar") %>% dplyr::group_by(id) %>% dplyr::mutate(value_perc = value/sum(value)) %>% dplyr::mutate(type="predicted")
comparison_best_params = rbind(select(ungroup(best_params_comparison), "key", "type", "value", 'value_perc'), select(actual_mix_2018_reduced, -X1, -year))
comparison_best_params %>% ggplot(aes(x=key, y=value_perc, fill=type)) + stat_summary(geom = "bar", fun.y = mean, position = "dodge2")+ stat_summary(geom = "errorbar", fun.data = mean_se, position = "dodge2") + ggtitle("Comparison of predicted vs actual for best parameter set over 10 from all runs")

## Getting MAPE for best param
predicted_means_best_param = dplyr::filter(run_1,dplyr::near(x=individual_c, y=best_params$individual_c[1], tol=0.1),dplyr::near(x=individual_m, y=best_params$individual_m[1], tol=0.1)) %>% gather("key", "value", "coal", "ccgt", "wind", "nuclear", "solar") %>% dplyr::group_by(id) %>% dplyr::mutate(value_perc = value/sum(value)) %>% dplyr::mutate(type="predicted") %>% dplyr::group_by(individual_c, individual_m, key) %>% dplyr::summarise(predicted_perc = mean(value_perc)) 
print(paste("MAPE = ", MAPE(predicted_means_best_param$predicted_perc, actual_mix_2018_reduced$value_perc)))
[1] "MAPE =  1.75551710439338"
p = best_params %>% transform(y=get_line(individual_c, individual_m), x=get_x())  %>% ggplot() + geom_line(aes(x=x.1, y=x))+ stat_smooth(data=pdc_example, aes(x=segment_demand, y=accepted_price), method="lm", col="yellow") + geom_point(data=pdc_example, aes(x=segment_demand, y=accepted_price)) + xlab("Demand (MW)") + ylab("Accepted Price") + ggtitle("Best paramater combination price curve")
p$labels$fill <- "Percentiles"
print(p)

Calculation of best parameters with lowest variance and error

ggsave("~/Documents/PhD/Projects/10-ELECSIM/notebooks/validation-optimisation/figures/introduction/best_run.pdf")
Saving 7 x 7 in image
RMSE(actuals,predicted)
[1] 0.04512687

best_params %>% transform(y=get_line(best_c, best_m), x=get_x())  %>% ggplot() + stat_smooth(data=pdc_example, aes(x=segment_demand, y=accepted_price, color="Simulated Fit (2018)"), method="lm") + geom_point(data=pdc_example, aes(x=segment_demand, y=accepted_price, color="PDC (2018)")) + geom_line(aes(x=x.1, y=x, color="PPDC"), size=2) + xlab("Demand (MW)") + ylab("Accepted Price (£/MWh)") + scale_color_manual(name = "Data",  values = c("PDC (2018)" = "orange", "PPDC" = "#306996", 'Simulated Fit (2018)'='red'))  + theme_classic() +theme(text = element_text(size=18))+ theme(aspect.ratio = 1, plot.margin=grid::unit(c(0,0,0,0), "mm")) 
best_params %>% transform(y=get_line(best_c, best_m), x=get_x())  %>% ggplot() + stat_smooth(data=pdc_example, aes(x=segment_demand, y=accepted_price, color="Simulated Fit (2018)"), method="lm") + geom_point(data=pdc_example, aes(x=segment_demand, y=accepted_price, color="PDC (2018)")) + geom_line(aes(x=x.1, y=x, color="PPDC"), size=2) + xlab("Demand (MW)") + ylab("Accepted Price (£/MWh)") + scale_color_manual(name = "Data",  values = c("PDC (2018)" = "orange", "PPDC" = "#306996", 'Simulated Fit (2018)'='red'))  + theme_classic() +theme(text = element_text(size=18))+ theme(aspect.ratio = 1, plot.margin=grid::unit(c(0,0,0,0), "mm")) 

ggsave("~/Documents/PhD/Projects/10-ELECSIM/notebooks/validation-optimisation/figures/results/best_run_price_dur_curve.pdf", dpi=1000)
Saving 6.89 x 4.26 in image

p=ggplot(run_1, aes(y=individual_m, x=individual_c)) + stat_summary_hex(aes(z = time_taken), bins=10) + facet_wrap(~ run_number) + scale_x_continuous(breaks = round(seq(min(run_1$individual_c), max(run_1$individual_c), by = 25),1)) + ggtitle("Hexagonal heatmap of input parameters against time taken with respect to population number")
p$labels$fill <- "Time \n Taken"
print(p)
ggsave('~/Desktop/time-taken-parameters.png')
Saving 6.89 x 4.26 in image

run_1 %>% arrange(desc(run_number)) %>% ggplot(alpha=0.1, aes(y=individual_m, x=individual_c)) + geom_point(aes(color=run_number, size=time_taken)) + ggtitle("Scatter plot showing run number against time taken and reward")

run_1 %>% filter(individual_c<-3, individual_m <0.0025, individual_m > 0.0015) %>% ggplot(aes(x=as.factor(run_number), y=time_taken)) + geom_violin() + ggtitle("Violin plot of time taken for each simulation run against population number")

ggplot(data=run_1, aes(x=as.factor(run_number), y=reward))+geom_boxplot()+geom_jitter(position=position_jitter(0.2), alpha=0.5, color='blue') + ggtitle("Boxplot and jitter of run number against reward")

run_1 %>% filter(individual_c<-3, individual_m <0.0025, individual_m > 0.0015) %>% ggplot(aes(x=as.factor(run_number), y=reward)) + geom_violin() + ggtitle("Violin plot of reward against population number")

ggplot(run_1, aes(x=reward, y=time_taken))+stat_smooth(method = "lm")+geom_point()+xlab("Absolute Percentage Error") + ggtitle("Scatter plot of time taken for each simulation run against \nabsolute percentage error")

dif_sum = run_1_long %>% inner_join(actual_mix_2018_reduced, by='key') %>% group_by(id,key) %>% mutate(total_difference = value.x-value.y) %>% ddply(.(id, key), summarise, difference_sum = sum(total_difference), time_taken=time_taken, reward=reward, run_number=run_number) %>% group_by(id) %>% summarise(tot_diff = sum(difference_sum), time_taken=mean(time_taken), reward=mean(reward), run_number=mean(run_number))

plot_ly(data=dif_sum, x=~tot_diff, y=~time_taken, z=~reward, type="scatter3d", mode="markers", color=~run_number) 
ggplot()+geom_point(data=run_1, aes(x=time_taken, y=reward, color=run_number)) + ggtitle("Scatter plot of time taken against reward")
run_1

run_1_long = gather(run_1, "key", "value", "coal", "ccgt", "wind", "nuclear", "solar")

# run_1_long %>% inner_join(actual_mix_2018_reduced, by='key') %>% group_by(id,key) %>% mutate(total_difference = value.x-value.y) %>% group_by(id, key) %>% summarise(difference_sum = sum(total_difference))

ggplot(data=dif_sum, aes(x=tot_diff, y=time_taken, color=reward)) + geom_point()+geom_smooth()+xlim(-11000,10000)

# actual_mix_2018_reduced
ggplot(data=dif_sum, aes(x=tot_diff, color=time_taken, y=reward)) + geom_point()+geom_smooth()+xlim(-11000,10000)
ggplot(run_1, aes(x=run_number, y=time_taken, color=reward)) + geom_point() +
   geom_smooth(method='lm')
<<<<<<< HEAD
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKCmBgYHtyfQpsaWJyYXJ5KCJ0aWR5dmVyc2UiKQpsaWJyYXJ5KCJnZ3Bsb3QyIikKbGlicmFyeShwbHlyKQpsaWJyYXJ5KCJtY28iKQpgYGAKYGBge3J9CnJ1bl8xID0gcmVhZF9jc3YoJy9Vc2Vycy9iMTAxNzU3OS9Eb2N1bWVudHMvUGhEL1Byb2plY3RzLzEwLUVMRUNTSU0vcnVuL3ZhbGlkYXRpb24tb3B0aW1pc2F0aW9uL2RhdGEvcnVuXzIuY3N2JykKdGFpbChydW5fMSkKYGBgCmBgYHtyfQpnZ3Bsb3QoZmlsdGVyKHJ1bl8xKSwgYWVzKHk9aW5kaXZpZHVhbF9tLCB4PWluZGl2aWR1YWxfYykpICsgZ2VvbV9oZXgoYmlucz0xMCkKYGBgCgpgYGB7cn0KcCA9IGdncGxvdChydW5fMSwgYWVzKHk9aW5kaXZpZHVhbF9tLCB4PWluZGl2aWR1YWxfYywgY29sb3I9cmV3YXJkKSwgc2l6ZT0xMCkgKyBmYWNldF93cmFwKH5ydW5fbnVtYmVyKSArIGdlb21fcG9pbnQoKSArIGdndGl0bGUoIlNjYXR0ZXIgcGxvdCBvZiBpbnB1dCBwYXJhbWV0ZXJzIGFuZCByZXdhcmQiKQpwJGxhYmVscyRmaWxsIDwtICJBYnNvbHV0ZSBcblBlcmNlbnRhZ2UgXG5FcnJvciIKcHJpbnQocCkKYGBgCmBgYHtyfQpwID0gZ2dwbG90KHJ1bl8xLCBhZXMoeT1pbmRpdmlkdWFsX20sIHg9aW5kaXZpZHVhbF9jLCBjb2xvcj1yZXdhcmQpLCBzaXplPTEwKSArIGZhY2V0X3dyYXAofnJ1bl9udW1iZXIpICsgZ2VvbV9qaXR0ZXIoKSArIGdndGl0bGUoIlNjYXR0ZXIgKGppdHRlcikgcGxvdCBvZiBpbnB1dCBwYXJhbWV0ZXJzIGFuZCByZXdhcmQiKQpwJGxhYmVscyRmaWxsIDwtICJBYnNvbHV0ZSBcblBlcmNlbnRhZ2UgXG5FcnJvciIKcHJpbnQocCkKYGBgCgoKYGBge3J9CnAgPSBnZ3Bsb3QocnVuXzEsIGFlcyh5PWluZGl2aWR1YWxfbSwgeD1pbmRpdmlkdWFsX2MsIGNvbG9yPXRpbWVfdGFrZW4pLCBzaXplPTEwKSArIGZhY2V0X3dyYXAofnJ1bl9udW1iZXIpICsgZ2VvbV9qaXR0ZXIoKSArIGdndGl0bGUoIlNjYXR0ZXIgcGxvdCBvZiBpbnB1dCBwYXJhbWV0ZXJzIGFuZCB0aW1lIHRha2VuIikKcCRsYWJlbHMkZmlsbCA8LSAiVGltZSBcblRha2VuIgpwcmludChwKQoKYGBgCgpgYGB7cn0KcD1nZ3Bsb3QocnVuXzEsIGFlcyh5PWluZGl2aWR1YWxfbSwgeD1pbmRpdmlkdWFsX2MpKSArIHN0YXRfc3VtbWFyeV9oZXgoYWVzKHogPSByZXdhcmQpLCBiaW5zPTEwKSArIGZhY2V0X3dyYXAofiBydW5fbnVtYmVyKSArIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSByb3VuZChzZXEobWluKHJ1bl8xJGluZGl2aWR1YWxfYyksIG1heChydW5fMSRpbmRpdmlkdWFsX2MpLCBieSA9IDI1KSwxKSkgKyBnZ3RpdGxlKCJIZXhhZ29uYWwgaGVhdG1hcCBvZiBpbnB1dCBwYXJhbWV0ZXJzIGFuZCBBYnNvbHV0ZSBQZXJjZW50YWdlIEVycm9yIikKcCRsYWJlbHMkZmlsbCA8LSAiQWJzb2x1dGUgXG5QZXJjZW50YWdlIFxuRXJyb3IiCnByaW50KHApCgpnZ3NhdmUoIn4vRGVza3RvcC9nZW5ldGljX2FsZ29yaXRobV9wcm9ncmVzc2lvbi5wbmciKQpgYGAKCmBgYHtyfQpydW5fMSAlPiUgZHBseXI6Omdyb3VwX2J5KHJ1bl9udW1iZXIpICU+JSBkcGx5cjo6c3VtbWFyaXNlKGF2Z19yZXdhcmQgPSBtZWFuKHJld2FyZCkpICU+JSBnZ3Bsb3QoKSsgZ2VvbV9zbW9vdGgoZGF0YT1ydW5fMSwgYWVzKHg9cnVuX251bWJlciwgcmV3YXJkKSkrZ2VvbV9saW5lKGFlcyh4PXJ1bl9udW1iZXIsIHk9YXZnX3Jld2FyZCkpK2dndGl0bGUoIkF2ZXJhZ2UgcmV3YXJkIHZzIFBvcHVsYXRpb24gTnVtYmVyIikgCmBgYAoKCgoKCmBgYHtyfQojIGFjY3VyYXRlX2FyZWEgPSBmaWx0ZXIocnVuXzEsIGluZGl2aWR1YWxfYzwtNC44LCBpbmRpdmlkdWFsX2M+LTUwLCBpbmRpdmlkdWFsX20gPDAuMDAzLCBpbmRpdmlkdWFsX20gPiAwLjAwMjMpCiMgYWNjdXJhdGVfYXJlYSA9IGZpbHRlcihydW5fMSwgcmV3YXJkIDwgMC4yKQojIGFjY3VyYXRlX2FyZWEgPSBmaWx0ZXIocnVuXzEsIHJ1bl9udW1iZXI9PTExKQphY2N1cmF0ZV9hcmVhID0gZmlsdGVyKHJ1bl8xLCBydW5fbnVtYmVyID09IDE2KQoKYWNjdXJhdGVfYXJlYQoKYGBgCgpgYGB7cn0KIGdncGxvdChkYXRhPWFjY3VyYXRlX2FyZWEsIGFlcyh4PWluZGl2aWR1YWxfYywgeT1pbmRpdmlkdWFsX20sIGNvbG9yPXJld2FyZCkpK2dlb21faml0dGVyKCkrZ2VvbV9wb2ludChjb2xvcj0icmVkIiwgYWxwaGE9MC41KSArIGdndGl0bGUoIlNjYXR0ZXIgYW5kIEppdHRlcnBsb3Qgb2YgUmV3YXJkIGFnYWluc3QgSW5wdXQgUGFyYW1ldGVycyBmb3IgXG5MYXN0IFBvcHVsYXRpb24gb2YgR0EiKQoKYGBgCgoKYGBge3J9CmFjY3VyYXRlX2FyZWFfbG9uZyA9IGdhdGhlcihhY2N1cmF0ZV9hcmVhLCAia2V5IiwgInZhbHVlIiwgImNvYWwiLCAiY2NndCIsICJ3aW5kIiwgIm51Y2xlYXIiLCAic29sYXIiKQphY2N1cmF0ZV9hcmVhX2xvbmdfcGVyYyA9IGFjY3VyYXRlX2FyZWFfbG9uZyAlPiUgZ3JvdXBfYnkoaWQpICU+JSBtdXRhdGUodmFsdWVfcGVyYyA9IHZhbHVlL3N1bSh2YWx1ZSkpCgpgYGAKCgpgYGB7cn0KcGFyYW1zX21vcmVfdGhhbl8xMCA9IHJ1bl8xICU+JSBncm91cF9ieShpbmRpdmlkdWFsX2MsIGluZGl2aWR1YWxfbSkgJT4lIGRwbHlyOjptdXRhdGUobnVtYmVyID0gbigpKSAlPiUgdW5ncm91cCgpICU+JSBmaWx0ZXIobnVtYmVyPiAxMCkgJT4lIGRwbHlyOjptdXRhdGVfaWYoaXMubnVtZXJpYywgcm91bmQsIDYpIAoKcGFyYW1zX21vcmVfdGhhbl8xMCAlPiUgZ2dwbG90KGFlcyhhcy5mYWN0b3IoaW5kaXZpZHVhbF9jKSwgcmV3YXJkKSkgK2dlb21fdmlvbGluKCkrZmFjZXRfd3JhcCh+aW5kaXZpZHVhbF9tKSsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkgK2dlb21faml0dGVyKHBvc2l0aW9uPXBvc2l0aW9uX2ppdHRlcigwLjIpLCBhbHBoYT0wLjA1KSArIGdndGl0bGUoIlZpb2xpbiBwbG90IG9mIGlucHV0IHBhcmFtZXRlcnMgd2l0aCBtb3JlIHRoYW4gMTAgc2ltdWxhdGlvbnMgXG5hZ2FpbnN0IGRpc3RyaWJ1dGlvbiBvZiByZXdhcmQiKQoKYGBgCgpgYGB7cn0KYWNjdXJhdGVfYXJlYSAlPiUgbXV0YXRlX2lmKGlzLm51bWVyaWMsIHJvdW5kLCA2KSAlPiUgZ2dwbG90KGFlcyhhcy5mYWN0b3IoaW5kaXZpZHVhbF9jKSwgcmV3YXJkKSkgK2dlb21fdmlvbGluKCkrZmFjZXRfd3JhcCh+aW5kaXZpZHVhbF9tKSsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkgK2dlb21faml0dGVyKHBvc2l0aW9uPXBvc2l0aW9uX2ppdHRlcigwLjIpKSsgZ2d0aXRsZSgiVmlvbGluIHBsb3Qgb2YgaW5wdXQgcGFyYW1ldGVycyB3aXRoIG1vcmUgdGhhbiAxMCBzaW11bGF0aW9ucyBvZiBsYXN0IHBvcHVsYXRpb24gb2YgR0FcbmFnYWluc3QgZGlzdHJpYnV0aW9uIG9mIHJld2FyZCIpCgpgYGAKCgpgYGB7cn0KYWN0dWFsX21peCA9IHJlYWRfY3N2KCcvVXNlcnMvYjEwMTc1NzkvRG9jdW1lbnRzL1BoRC9Qcm9qZWN0cy8xMC1FTEVDU0lNL2VsZWNzaW0vZGF0YS9wcm9jZXNzZWQvZWxlY3RyaWNpdHlfbWl4L2VuZXJneV9taXhfaGlzdG9yaWNhbC5jc3YnKQphY3R1YWxfbWl4XzIwMTggPSBmaWx0ZXIoYWN0dWFsX21peCwgeWVhcj09MjAxOCkKCgphY3R1YWxfbWl4XzIwMTgkdHlwZSA9ICJhY3R1YWwiCgphY3R1YWxfbWl4XzIwMTgKYGBgCgpgYGB7cn0KYWN0dWFsX21peF8yMDE4X3JlZHVjZWQgPSBmaWx0ZXIoYWN0dWFsX21peF8yMDE4LCB2YXJpYWJsZSAlaW4lIGMoImNjZ3QiLCAnd2luZCcsICdudWNsZWFyJywgJ3NvbGFyJywgJ2NvYWwnKSkKYWN0dWFsX21peF8yMDE4X3JlZHVjZWQgPSBhY3R1YWxfbWl4XzIwMThfcmVkdWNlZCAlPiUgbXV0YXRlKHZhbHVlX3BlcmMgPSB2YWx1ZS9zdW0odmFsdWUpKQphY3R1YWxfbWl4XzIwMThfcmVkdWNlZCA9IGRwbHlyOjpyZW5hbWUoYWN0dWFsX21peF8yMDE4X3JlZHVjZWQsIGtleT12YXJpYWJsZSkKaGVhZChhY3R1YWxfbWl4XzIwMThfcmVkdWNlZCkKYGBgCmBgYHtyfQphY2N1cmF0ZV9hcmVhX2xvbmdfcGVyYyR0eXBlID0gJ3ByZWRpY3RlZCcKYWNjdXJhdGVfYXJlYV9sb25nX3BlcmMKCmNvbXBhcmlzb24gPSByYmluZChzZWxlY3QodW5ncm91cChhY2N1cmF0ZV9hcmVhX2xvbmdfcGVyYyksICJrZXkiLCAidHlwZSIsICJ2YWx1ZSIsICd2YWx1ZV9wZXJjJyksIHNlbGVjdChhY3R1YWxfbWl4XzIwMThfcmVkdWNlZCwgLVgxLCAteWVhcikpCmBgYAoKCgoKCmBgYHtyfQpnZ3Bsb3QoY29tcGFyaXNvbiwgYWVzKHg9a2V5LCB5PXZhbHVlX3BlcmMsIGZpbGw9dHlwZSkpICsKICBzdGF0X3N1bW1hcnkoZ2VvbSA9ICJiYXIiLCBmdW4ueSA9IG1lYW4sIHBvc2l0aW9uID0gImRvZGdlMiIpKyBzdGF0X3N1bW1hcnkoZ2VvbSA9ICJlcnJvcmJhciIsIGZ1bi5kYXRhID0gbWVhbl9zZSwgcG9zaXRpb24gPSAiZG9kZ2UyIikgKyB5bGFiKCJFbmVyZ3kgTWl4ICglKSIpICsgZ2d0aXRsZSgiQ29tYmluYXRpb24gb2YgYWxsIHJ1bnMgaW4gbGFzdCBnZW5ldGljIGFsZ29yaXRobSBydW4iKQoKZ2dzYXZlKCd+L0Rlc2t0b3AvYXZlcmFnZV9lcnJvcl9vZl9iZXN0X3BhcmFtcy5wbmcnKQpgYGAKCmBgYHtyfQpiZXN0X3Jlc3VsdCA9IHJ1bl8xICU+JSBncm91cF9ieSgiaWQiKSAlPiUgZmlsdGVyKHJld2FyZD09bWluKHJld2FyZCkpICU+JSBnYXRoZXIoImtleSIsICJ2YWx1ZSIsICJjb2FsIiwgImNjZ3QiLCAid2luZCIsICJudWNsZWFyIiwgInNvbGFyIikgJT4lIGdyb3VwX2J5KGlkKSAlPiUgbXV0YXRlKHZhbHVlX3BlcmMgPSB2YWx1ZS9zdW0odmFsdWUpKSAlPiUgbXV0YXRlKHR5cGU9InByZWRpY3RlZCIpCgpjb21wYXJpc29uX2Jlc3QgPSByYmluZChzZWxlY3QodW5ncm91cChiZXN0X3Jlc3VsdCksICJrZXkiLCAidHlwZSIsICJ2YWx1ZSIsICd2YWx1ZV9wZXJjJyksIHNlbGVjdChhY3R1YWxfbWl4XzIwMThfcmVkdWNlZCwgLVgxLCAteWVhcikpCgpnZ3Bsb3QoY29tcGFyaXNvbl9iZXN0LCBhZXMoeD1rZXksIHk9dmFsdWVfcGVyYywgZmlsbD10eXBlKSkgKyBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZTIiKSArIHlsYWIoIkVuZXJneSBNaXggKCUpIikgKyBnZ3RpdGxlKCJCZXN0IHNpbmdsZSBydW4iKQpgYGAKCgpgYGB7cn0KcGRjX2V4YW1wbGUgPSByZWFkX2NzdignL1VzZXJzL2IxMDE3NTc5L0RvY3VtZW50cy9QaEQvUHJvamVjdHMvMTAtRUxFQ1NJTS9ub3RlYm9va3MvdmFsaWRhdGlvbi1vcHRpbWlzYXRpb24vZGF0YS9wcmljZV9kZW1hbmRfY3VydmVfZXhhbXBsZS5jc3YnKQoKCmRlbWFuZF9yYW5nZSA9IGRhdGEuZnJhbWUoeD1zZXEoZnJvbT1taW4ocGRjX2V4YW1wbGUkc2VnbWVudF9kZW1hbmQpLG1heChwZGNfZXhhbXBsZSRzZWdtZW50X2RlbWFuZCksbGVuZ3RoLm91dD01MDApKQoKZ2V0X2xpbmUgPSBmdW5jdGlvbihjLCBtKXsKICAgIHkgPSBtICogZGVtYW5kX3JhbmdlICsgYwogICAgcmV0dXJuKHkpCn0KCmdldF94ID0gZnVuY3Rpb24oKXsKICAgIHJldHVybihkZW1hbmRfcmFuZ2UpCn0KCiMgbGluZXMgPSBhY2N1cmF0ZV9hcmVhICU+JSBncm91cF9ieShpZCkgJT4lIGFwcGx5KGdldF9saW5lKC4pKQoKbGluZXMgPSBkZHBseShhY2N1cmF0ZV9hcmVhLCAuKGlkKSwgdHJhbnNmb3JtLCB5PWdldF9saW5lKGluZGl2aWR1YWxfYywgaW5kaXZpZHVhbF9tKSwgeD1nZXRfeCgpKQoKCmdncGxvdCgpICsgZ2VvbV9saW5lKGRhdGE9bGluZXMsIGFlcyh4PXguMSwgeT14LCBncm91cD1pZCwgY29sb3I9cmV3YXJkKSkgKyBzdGF0X3Ntb290aChkYXRhPXBkY19leGFtcGxlLCBhZXMoeD1zZWdtZW50X2RlbWFuZCwgeT1hY2NlcHRlZF9wcmljZSksIG1ldGhvZD0ibG0iLCBjb2w9InJlZCIpICsgZ2VvbV9wb2ludChkYXRhPXBkY19leGFtcGxlLCBhZXMoeD1zZWdtZW50X2RlbWFuZCwgeT1hY2NlcHRlZF9wcmljZSkpICsgeGxhYigiRGVtYW5kIChNVykiKSArIHlsYWIoIkFjY2VwdGVkIFByaWNlIikgKyBnZ3RpdGxlKCJMYXN0IGdlbmV0aWMgYWxnb3JpdGhtIHJ1biBwcmljZSBjdXJ2ZXMgYmV0d2VlbiAyMDIzLTIwMjggXG5jb21wYXJlZCB0byBwcmljZSBpbiAyMDE4IikKCmBgYAoKYGBge3J9CmJlc3RfNzVfcGVyY2VudGlsZSA9IGFjY3VyYXRlX2FyZWEgJT4lIGdyb3VwX2J5KGluZGl2aWR1YWxfYywgaW5kaXZpZHVhbF9tKSAlPiUgZHBseXI6OnN1bW1hcmlzZShudW1iZXI9bigpLCBxdWFudGlsZXMgPSBsaXN0KGVuZnJhbWUocXVhbnRpbGUocmV3YXJkLCBwcm9icz1jKDAuMjUsMC41LDAuNzUpKSkpKSAlPiUgdW5uZXN0ICU+JSB1bmdyb3VwKCkgJT4lIGZpbHRlcihudW1iZXI+MTApICU+JSBncm91cF9ieShuYW1lKSAlPiVmaWx0ZXIocmFuayh2YWx1ZSwgdGllcy5tZXRob2Q9ImZpcnN0Iik9PTEpCgpwID0gZGRwbHkoYmVzdF83NV9wZXJjZW50aWxlLCAuKG5hbWUpLCB0cmFuc2Zvcm0sIHk9Z2V0X2xpbmUoaW5kaXZpZHVhbF9jLCBpbmRpdmlkdWFsX20pLCB4PWdldF94KCkpICAlPiUgZ2dwbG90KCkgKyBnZW9tX2xpbmUoYWVzKHg9eC4xLCB5PXgsIGNvbG9yPW5hbWUpKSsgc3RhdF9zbW9vdGgoZGF0YT1wZGNfZXhhbXBsZSwgYWVzKHg9c2VnbWVudF9kZW1hbmQsIHk9YWNjZXB0ZWRfcHJpY2UpLCBtZXRob2Q9ImxtIiwgY29sPSJ5ZWxsb3ciKSArIGdlb21fcG9pbnQoZGF0YT1wZGNfZXhhbXBsZSwgYWVzKHg9c2VnbWVudF9kZW1hbmQsIHk9YWNjZXB0ZWRfcHJpY2UpKSArIHhsYWIoIkRlbWFuZCAoTVcpIikgKyB5bGFiKCJBY2NlcHRlZCBQcmljZSIpICsgZ2d0aXRsZSgiUHJpY2UgY3VydmUgb2YgYmVzdCBydW5zIGF0IGRpZmZlcmVudCBwZXJjZW50aWxlcyBvZiBsYXN0IGdlbmV0aWMgXG5hbGdvcml0aG0gcG9wdWxhdGlvbiIpCnAkbGFiZWxzJGZpbGwgPC0gIlBlcmNlbnRpbGVzIgpwcmludChwKQpgYGAKYGBge3J9CmJlc3RfcGVyY2VudGlsZXNfY29tcGFyaXNvbiA9IGlubmVyX2pvaW4oYWNjdXJhdGVfYXJlYSwgYmVzdF83NV9wZXJjZW50aWxlLCBieT1jKCdpbmRpdmlkdWFsX2MnLCAnaW5kaXZpZHVhbF9tJykpICU+JSBnYXRoZXIoImtleSIsICJ2YWx1ZSIsICJjb2FsIiwgImNjZ3QiLCAid2luZCIsICJudWNsZWFyIiwgInNvbGFyIikgJT4lIGdyb3VwX2J5KGlkKSAlPiUgbXV0YXRlKHZhbHVlX3BlcmMgPSB2YWx1ZS9zdW0odmFsdWUpKSAlPiUgbXV0YXRlKHR5cGU9bmFtZSkKCmNvbXBhcmlzb25fcGVyY2VudGlsZXMgPSByYmluZChzZWxlY3QodW5ncm91cChiZXN0X3BlcmNlbnRpbGVzX2NvbXBhcmlzb24pLCAia2V5IiwgInR5cGUiLCAidmFsdWUiLCAndmFsdWVfcGVyYycpLCBzZWxlY3QoYWN0dWFsX21peF8yMDE4X3JlZHVjZWQsIC1YMSwgLXllYXIpKQoKY29tcGFyaXNvbl9wZXJjZW50aWxlcyAlPiUgZ2dwbG90KGFlcyh4PWtleSwgeT12YWx1ZV9wZXJjLCBmaWxsPXR5cGUpKSArIHN0YXRfc3VtbWFyeShnZW9tID0gImJhciIsIGZ1bi55ID0gbWVhbiwgcG9zaXRpb24gPSAiZG9kZ2UyIikrIHN0YXRfc3VtbWFyeShnZW9tID0gImVycm9yYmFyIiwgZnVuLmRhdGEgPSBtZWFuX3NlLCBwb3NpdGlvbiA9ICJkb2RnZTIiKSArIGdndGl0bGUoIkNvbXBhcmlzb24gb2YgZW5lcmd5IG1peCBvZiBmaW5hbCBnZW5ldGljIGFsZ29yaXRobSBwb3B1bGF0aW9uIFxuYXQgZGlmZmVyZW50IHF1YW50aWxlIGxldmVscyIpCgoKYGBgCmBgYHtyfQpyYmluZChmaWx0ZXIoc2VsZWN0KHVuZ3JvdXAoYmVzdF9wZXJjZW50aWxlc19jb21wYXJpc29uKSwgImtleSIsICJ0eXBlIiwgInZhbHVlIiwgJ3ZhbHVlX3BlcmMnKSx0eXBlPT0iNTAlIiksIHNlbGVjdChhY3R1YWxfbWl4XzIwMThfcmVkdWNlZCwgLVgxLCAteWVhcikpICU+JSBnZ3Bsb3QoYWVzKHg9a2V5LCB5PXZhbHVlX3BlcmMsIGZpbGw9dHlwZSkpICsgc3RhdF9zdW1tYXJ5KGdlb20gPSAiYmFyIiwgZnVuLnkgPSBtZWFuLCBwb3NpdGlvbiA9ICJkb2RnZTIiKSsgc3RhdF9zdW1tYXJ5KGdlb20gPSAiZXJyb3JiYXIiLCBmdW4uZGF0YSA9IG1lYW5fc2UsIHBvc2l0aW9uID0gImRvZGdlMiIpICsgZ2d0aXRsZSgiQmVzdCBwYXJhbWV0ZXIgY29tYmluYXRpb25zIGZyb20gZmluYWwgZ2VuZXRpYyBhbGdvcml0aG0gcnVuIikKCmBgYAoKCiMjIEJFU1QgUEFSQU1FVEVSIENPTUJJTkFUSU9OIEZST00gQUxMIFJVTlMKCmBgYHtyfQpiZXN0Xzc1X3BlcmNlbnRpbGVfYWxsX3J1bnMgPSBydW5fMSAlPiUgZ3JvdXBfYnkoaW5kaXZpZHVhbF9jLCBpbmRpdmlkdWFsX20pICU+JSBkcGx5cjo6c3VtbWFyaXNlKG51bWJlcj1uKCksIHF1YW50aWxlcyA9IGxpc3QoZW5mcmFtZShxdWFudGlsZShyZXdhcmQsIHByb2JzPWMoMC4yNSwwLjUsMC43NSwgMC45LCAxLjApKSkpKSAlPiUgdW5uZXN0ICU+JSB1bmdyb3VwKCkgJT4lIGZpbHRlcihudW1iZXI+MTApICU+JSBncm91cF9ieShuYW1lKSAlPiVmaWx0ZXIocmFuayh2YWx1ZSwgdGllcy5tZXRob2Q9ImZpcnN0Iik9PTEpCgpwID0gZGRwbHkoYmVzdF83NV9wZXJjZW50aWxlX2FsbF9ydW5zLCAuKG5hbWUpLCB0cmFuc2Zvcm0sIHk9Z2V0X2xpbmUoaW5kaXZpZHVhbF9jLCBpbmRpdmlkdWFsX20pLCB4PWdldF94KCkpICAlPiUgZ2dwbG90KCkgKyBnZW9tX2xpbmUoYWVzKHg9eC4xLCB5PXgsIGNvbG9yPW5hbWUpKSsgc3RhdF9zbW9vdGgoZGF0YT1wZGNfZXhhbXBsZSwgYWVzKHg9c2VnbWVudF9kZW1hbmQsIHk9YWNjZXB0ZWRfcHJpY2UpLCBtZXRob2Q9ImxtIiwgY29sPSJ5ZWxsb3ciKSArIGdlb21fcG9pbnQoZGF0YT1wZGNfZXhhbXBsZSwgYWVzKHg9c2VnbWVudF9kZW1hbmQsIHk9YWNjZXB0ZWRfcHJpY2UpKSArIHhsYWIoIkRlbWFuZCAoTVcpIikgKyB5bGFiKCJBY2NlcHRlZCBQcmljZSIpICsgZ2d0aXRsZSgiUGVyY2VudGlsZXMgZnJvbSBhbGwgcnVucyIpCnAkbGFiZWxzJGZpbGwgPC0gIlBlcmNlbnRpbGVzIgpwcmludChwKQpgYGAKYGBge3J9CmJlc3RfcGVyY2VudGlsZXNfY29tcGFyaXNvbiA9IGlubmVyX2pvaW4ocnVuXzEsIGJlc3RfNzVfcGVyY2VudGlsZV9hbGxfcnVucywgYnk9YygnaW5kaXZpZHVhbF9jJywgJ2luZGl2aWR1YWxfbScpKSAlPiUgZ2F0aGVyKCJrZXkiLCAidmFsdWUiLCAiY29hbCIsICJjY2d0IiwgIndpbmQiLCAibnVjbGVhciIsICJzb2xhciIpICU+JSBncm91cF9ieShpZCkgJT4lIG11dGF0ZSh2YWx1ZV9wZXJjID0gdmFsdWUvc3VtKHZhbHVlKSkgJT4lIG11dGF0ZSh0eXBlPW5hbWUpCgpjb21wYXJpc29uX3BlcmNlbnRpbGVzID0gcmJpbmQoc2VsZWN0KHVuZ3JvdXAoYmVzdF9wZXJjZW50aWxlc19jb21wYXJpc29uKSwgImtleSIsICJ0eXBlIiwgInZhbHVlIiwgJ3ZhbHVlX3BlcmMnKSwgc2VsZWN0KGFjdHVhbF9taXhfMjAxOF9yZWR1Y2VkLCAtWDEsIC15ZWFyKSkKCmNvbXBhcmlzb25fcGVyY2VudGlsZXMgJT4lIGdncGxvdChhZXMoeD1rZXksIHk9dmFsdWVfcGVyYywgZmlsbD10eXBlKSkgKyBzdGF0X3N1bW1hcnkoZ2VvbSA9ICJiYXIiLCBmdW4ueSA9IG1lYW4sIHBvc2l0aW9uID0gImRvZGdlMiIpKyBzdGF0X3N1bW1hcnkoZ2VvbSA9ICJlcnJvcmJhciIsIGZ1bi5kYXRhID0gbWVhbl9zZSwgcG9zaXRpb24gPSAiZG9kZ2UyIikKYGBgCmBgYHtyfQpyYmluZChmaWx0ZXIoc2VsZWN0KHVuZ3JvdXAoYmVzdF9wZXJjZW50aWxlc19jb21wYXJpc29uKSwgImtleSIsICJ0eXBlIiwgInZhbHVlIiwgJ3ZhbHVlX3BlcmMnKSx0eXBlPT0iNzUlIiB8IHR5cGU9PSI5MCUiKSwgc2VsZWN0KGFjdHVhbF9taXhfMjAxOF9yZWR1Y2VkLCAtWDEsIC15ZWFyKSkgJT4lIGdncGxvdChhZXMoeD1rZXksIHk9dmFsdWVfcGVyYywgZmlsbD10eXBlKSkgKyBzdGF0X3N1bW1hcnkoZ2VvbSA9ICJiYXIiLCBmdW4ueSA9IG1lYW4sIHBvc2l0aW9uID0gImRvZGdlMiIpKyBzdGF0X3N1bW1hcnkoZ2VvbSA9ICJlcnJvcmJhciIsIGZ1bi5kYXRhID0gbWVhbl9zZSwgcG9zaXRpb24gPSAiZG9kZ2UyIikgKyBnZ3RpdGxlKCJCZXN0IHBhcmFtZXRlciBjb21iaW5hdGlvbnMgZnJvbSBhbGwgZ2VuZXRpYyBhbGdvcml0aG0gcnVucyIpCgpgYGAKCiMjIENhbGN1bGF0aW9uIG9mIGJlc3QgcXVhbnRpbGUgdG8gc2VsZWN0IGNvbWJpbmF0aW9uIG9mIHBhcmFtZXRlcnMgZm9yIGxvd2VzdCByZXdhcmQKCmBgYHtyfQpiZXN0X3BhcmFtcyA9IHBhcmFtc19tb3JlX3RoYW5fMTAgJT4lIGdyb3VwX2J5KGluZGl2aWR1YWxfYywgaW5kaXZpZHVhbF9tKSAlPiUgZ2F0aGVyKCJrZXkiLCAidmFsdWUiLCAiY29hbCIsICJjY2d0IiwgIndpbmQiLCAibnVjbGVhciIsICJzb2xhciIpICU+JSBncm91cF9ieShpZCkgJT4lIG11dGF0ZSh2YWx1ZV9wZXJjID0gdmFsdWUvc3VtKHZhbHVlKSkgJT4lIGdyb3VwX2J5KGlkLCBrZXkpICU+JSBpbm5lcl9qb2luKGFjdHVhbF9taXhfMjAxOF9yZWR1Y2VkLCBieT0ia2V5IikgJT4lIG11dGF0ZShkaWZmX3BlcmMgPSBhYnModmFsdWVfcGVyYy54LXZhbHVlX3BlcmMueSkpICU+JSBncm91cF9ieShpZCkgJT4lIHN1bW1hcmlzZShtZWFuX2RpZmZfcGVyYyA9IG1lYW4oZGlmZl9wZXJjKSwgaW5kaXZpZHVhbF9jID0gbWVhbihpbmRpdmlkdWFsX2MpLCBpbmRpdmlkdWFsX20gPSBtZWFuKGluZGl2aWR1YWxfbSkpICU+JSBmaWx0ZXIocmFuayhtZWFuX2RpZmZfcGVyYywgdGllcy5tZXRob2Q9ImZpcnN0Iik9PTEpCgpiZXN0X3BhcmFtc19jb21wYXJpc29uID0gZmlsdGVyKHJ1bl8xLGRwbHlyOjpuZWFyKHg9aW5kaXZpZHVhbF9jLCB5PWJlc3RfcGFyYW1zJGluZGl2aWR1YWxfY1sxXSwgdG9sPTAuMDAwMDEpLGRwbHlyOjpuZWFyKHg9aW5kaXZpZHVhbF9tLCB5PWJlc3RfcGFyYW1zJGluZGl2aWR1YWxfbVsxXSwgdG9sPTAuMDAwMDEpKSAlPiUgZ2F0aGVyKCJrZXkiLCAidmFsdWUiLCAiY29hbCIsICJjY2d0IiwgIndpbmQiLCAibnVjbGVhciIsICJzb2xhciIpICU+JSBkcGx5cjo6Z3JvdXBfYnkoaWQpICU+JSBkcGx5cjo6bXV0YXRlKHZhbHVlX3BlcmMgPSB2YWx1ZS9zdW0odmFsdWUpKSAlPiUgZHBseXI6Om11dGF0ZSh0eXBlPSJwcmVkaWN0ZWQiKQoKY29tcGFyaXNvbl9iZXN0X3BhcmFtcyA9IHJiaW5kKHNlbGVjdCh1bmdyb3VwKGJlc3RfcGFyYW1zX2NvbXBhcmlzb24pLCAia2V5IiwgInR5cGUiLCAidmFsdWUiLCAndmFsdWVfcGVyYycpLCBzZWxlY3QoYWN0dWFsX21peF8yMDE4X3JlZHVjZWQsIC1YMSwgLXllYXIpKQoKY29tcGFyaXNvbl9iZXN0X3BhcmFtcyAlPiUgZ2dwbG90KGFlcyh4PWtleSwgeT12YWx1ZV9wZXJjLCBmaWxsPXR5cGUpKSArIHN0YXRfc3VtbWFyeShnZW9tID0gImJhciIsIGZ1bi55ID0gbWVhbiwgcG9zaXRpb24gPSAiZG9kZ2UyIikrIHN0YXRfc3VtbWFyeShnZW9tID0gImVycm9yYmFyIiwgZnVuLmRhdGEgPSBtZWFuX3NlLCBwb3NpdGlvbiA9ICJkb2RnZTIiKSArIGdndGl0bGUoIkNvbXBhcmlzb24gb2YgcHJlZGljdGVkIHZzIGFjdHVhbCBmb3IgYmVzdCBwYXJhbWV0ZXIgc2V0IG92ZXIgMTAgZnJvbSBhbGwgcnVucyIpCgoKCiMjIEdldHRpbmcgTUFQRSBmb3IgYmVzdCBwYXJhbQoKcHJlZGljdGVkX21lYW5zX2Jlc3RfcGFyYW0gPSBkcGx5cjo6ZmlsdGVyKHJ1bl8xLGRwbHlyOjpuZWFyKHg9aW5kaXZpZHVhbF9jLCB5PWJlc3RfcGFyYW1zJGluZGl2aWR1YWxfY1sxXSwgdG9sPTAuMSksZHBseXI6Om5lYXIoeD1pbmRpdmlkdWFsX20sIHk9YmVzdF9wYXJhbXMkaW5kaXZpZHVhbF9tWzFdLCB0b2w9MC4xKSkgJT4lIGdhdGhlcigia2V5IiwgInZhbHVlIiwgImNvYWwiLCAiY2NndCIsICJ3aW5kIiwgIm51Y2xlYXIiLCAic29sYXIiKSAlPiUgZHBseXI6Omdyb3VwX2J5KGlkKSAlPiUgZHBseXI6Om11dGF0ZSh2YWx1ZV9wZXJjID0gdmFsdWUvc3VtKHZhbHVlKSkgJT4lIGRwbHlyOjptdXRhdGUodHlwZT0icHJlZGljdGVkIikgJT4lIGRwbHlyOjpncm91cF9ieShpbmRpdmlkdWFsX2MsIGluZGl2aWR1YWxfbSwga2V5KSAlPiUgZHBseXI6OnN1bW1hcmlzZShwcmVkaWN0ZWRfcGVyYyA9IG1lYW4odmFsdWVfcGVyYykpIAoKcHJpbnQocGFzdGUoIk1BUEUgPSAiLCBNQVBFKHByZWRpY3RlZF9tZWFuc19iZXN0X3BhcmFtJHByZWRpY3RlZF9wZXJjLCBhY3R1YWxfbWl4XzIwMThfcmVkdWNlZCR2YWx1ZV9wZXJjKSkpCgpgYGAKCmBgYHtyfQpwID0gYmVzdF9wYXJhbXMgJT4lIHRyYW5zZm9ybSh5PWdldF9saW5lKGluZGl2aWR1YWxfYywgaW5kaXZpZHVhbF9tKSwgeD1nZXRfeCgpKSAgJT4lIGdncGxvdCgpICsgZ2VvbV9saW5lKGFlcyh4PXguMSwgeT14KSkrIHN0YXRfc21vb3RoKGRhdGE9cGRjX2V4YW1wbGUsIGFlcyh4PXNlZ21lbnRfZGVtYW5kLCB5PWFjY2VwdGVkX3ByaWNlKSwgbWV0aG9kPSJsbSIsIGNvbD0ieWVsbG93IikgKyBnZW9tX3BvaW50KGRhdGE9cGRjX2V4YW1wbGUsIGFlcyh4PXNlZ21lbnRfZGVtYW5kLCB5PWFjY2VwdGVkX3ByaWNlKSkgKyB4bGFiKCJEZW1hbmQgKE1XKSIpICsgeWxhYigiQWNjZXB0ZWQgUHJpY2UiKSArIGdndGl0bGUoIkJlc3QgcGFyYW1hdGVyIGNvbWJpbmF0aW9uIHByaWNlIGN1cnZlIikKcCRsYWJlbHMkZmlsbCA8LSAiUGVyY2VudGlsZXMiCnByaW50KHApCgpgYGAKCgojIENhbGN1bGF0aW9uIG9mIGJlc3QgcGFyYW1ldGVycyB3aXRoIGxvd2VzdCB2YXJpYW5jZSBhbmQgZXJyb3IKYGBge3J9CiMgYmVzdF9wYXJhbXMgPSBwYXJhbXNfbW9yZV90aGFuXzEwICU+JSBncm91cF9ieShpbmRpdmlkdWFsX2MsIGluZGl2aWR1YWxfbSkgJT4lIGdhdGhlcigia2V5IiwgInZhbHVlIiwgImNvYWwiLCAiY2NndCIsICJ3aW5kIiwgIm51Y2xlYXIiLCAic29sYXIiKSAlPiUgZ3JvdXBfYnkoaWQpICU+JSBtdXRhdGUodmFsdWVfcGVyYyA9IHZhbHVlL3N1bSh2YWx1ZSkpICU+JSBncm91cF9ieShpZCwga2V5KSAlPiUgaW5uZXJfam9pbihhY3R1YWxfbWl4XzIwMThfcmVkdWNlZCwgYnk9ImtleSIpICU+JSBtdXRhdGUoZGlmZl9wZXJjID0gYWJzKHZhbHVlX3BlcmMueC12YWx1ZV9wZXJjLnkpKSAlPiUgZ3JvdXBfYnkoaWQpICU+JSBzdW1tYXJpc2UobWVhbl9kaWZmX3BlcmMgPSBtZWFuKGRpZmZfcGVyYyksIGluZGl2aWR1YWxfYyA9IG1lYW4oaW5kaXZpZHVhbF9jKSwgaW5kaXZpZHVhbF9tID0gbWVhbihpbmRpdmlkdWFsX20pKSAlPiUgZmlsdGVyKHJhbmsobWVhbl9kaWZmX3BlcmMsIHRpZXMubWV0aG9kPSJmaXJzdCIpPT0xKQoKIyBjYWxjdWxhdGVfbWVhbl9lcnJvciA9IGZ1bmN0aW9uKGRmKXsKIyAgICAgCiMgICAgIHJldHVybihnYXRoZXIoZGYsICJrZXkiLCAidmFsdWUiLCAiY29hbCIsICJjY2d0IiwgIndpbmQiLCAibnVjbGVhciIsICJzb2xhciIpICU+JSBpbm5lcl9qb2luKGFjdHVhbF9taXhfMjAxOF9yZWR1Y2VkLCBieT0na2V5JykpCiMgfQoKIyBwYXJhbXNfbW9yZV90aGFuXzEwICU+JSBncm91cF9ieShpbmRpdmlkdWFsX2MsIGluZGl2aWR1YWxfbSkgJT4lIGRvKC4sIGNhbGN1bGF0ZV9tZWFuX2Vycm9yKQojIGRkcGx5KHBhcmFtc19tb3JlX3RoYW5fMTAsIC4oaW5kaXZpZHVhbF9jLCBpbmRpdmlkdWFsX20pLCBjYWxjdWxhdGVfbWVhbl9lcnJvcikKCnBhcmFtc19zZF9tZWFuX3Jld2FyZCA9IHBhcmFtc19tb3JlX3RoYW5fMTAgJT4lIGRwbHlyOjpncm91cF9ieShpbmRpdmlkdWFsX2MsIGluZGl2aWR1YWxfbSkgJT4lIGdhdGhlcigia2V5IiwgInZhbHVlIiwgImNvYWwiLCAiY2NndCIsICJ3aW5kIiwgIm51Y2xlYXIiLCAic29sYXIiKSAlPiUgZHBseXI6Omdyb3VwX2J5KGlkKSAlPiUgZHBseXI6Om11dGF0ZSh2YWx1ZV9wZXJjID0gdmFsdWUvc3VtKHZhbHVlKSkgJT4lIGRwbHlyOjpncm91cF9ieShpZCwga2V5KSAlPiUgZHBseXI6OmlubmVyX2pvaW4oYWN0dWFsX21peF8yMDE4X3JlZHVjZWQsIGJ5PSJrZXkiKSAlPiUgZHBseXI6Om11dGF0ZShkaWZmX3BlcmMgPSBhYnModmFsdWVfcGVyYy54LXZhbHVlX3BlcmMueSkpICU+JSBkcGx5cjo6Z3JvdXBfYnkoaWQpICU+JSBkcGx5cjo6c3VtbWFyaXNlKGRpZmZfc2QgPSBzZChkaWZmX3BlcmMpLCBtZWFuX2RpZmZfcGVyYyA9IG1lYW4oZGlmZl9wZXJjKSwgaW5kaXZpZHVhbF9jID0gbWVhbihpbmRpdmlkdWFsX2MpLCBpbmRpdmlkdWFsX20gPSBtZWFuKGluZGl2aWR1YWxfbSkpICU+JSBkcGx5cjo6Z3JvdXBfYnkoaW5kaXZpZHVhbF9jLCBpbmRpdmlkdWFsX20pICU+JSBkcGx5cjo6c3VtbWFyaXNlKGRpZmZfc2QgPSBzZChkaWZmX3NkKSwgbWVhbl9kaWZmX3BlcmMgPSBkcGx5cjo6bWVhbihtZWFuX2RpZmZfcGVyYykpCgpwYXJhbXNfc2RfbWVhbl9yZXdhcmRfb3JkZXJlZCA9IGFycmFuZ2UocGFyYW1zX3NkX21lYW5fcmV3YXJkLCBkaWZmX3NkLCBtZWFuX2RpZmZfcGVyYykKZnJvbnRpZXIgPSBnZXRfZnJvbnRpZXIoYXMuZGF0YS5mcmFtZShwYXJhbXNfc2RfbWVhbl9yZXdhcmRfb3JkZXJlZCksIGRpZmZfc2QsIG1lYW5fZGlmZl9wZXJjLCBkZWNyZWFzaW5nID0gRkFMU0UsIHF1YWRyYW50ID0gImJvdHRvbS5sZWZ0IikKCnBhcmFtc19zZF9tZWFuX3Jld2FyZCAlPiUgZ2dwbG90KCkgKyBnZW9tX3BvaW50KGFlcyhkaWZmX3NkLCBtZWFuX2RpZmZfcGVyYykpICsgZ2VvbV9saW5lKGRhdGE9ZnJvbnRpZXIsIGFlcyhkaWZmX3NkLCBtZWFuX2RpZmZfcGVyYyksIGNvbG9yPSJyZWQiKSArIGdndGl0bGUoIlBhcmV0byBmcm9udGllciBvZiBzdGFuZGFyZCBkZXZpYXRpb24gdmVyc3VzIG1lYW4gZm9yIHNpbXVsYXRpb25zIFxub2YgbW9yZSB0aGFuIDEwIHJ1bnMiKQoKYGBgCgpgYGB7cn0KcGFyYW1zX21vcmVfdGhhbl8xMF9wZXJjID0gcGFyYW1zX21vcmVfdGhhbl8xMCAlPiUgZHBseXI6Omdyb3VwX2J5KGluZGl2aWR1YWxfYywgaW5kaXZpZHVhbF9tKSAlPiUgZ2F0aGVyKCJrZXkiLCAidmFsdWUiLCAiY29hbCIsICJjY2d0IiwgIndpbmQiLCAibnVjbGVhciIsICJzb2xhciIpICU+JSBncm91cF9ieShpZCkgJT4lIGRwbHlyOjptdXRhdGUodmFsdWVfcGVyYyA9IHZhbHVlL3N1bSh2YWx1ZSkpCgpmcm9udGllcl9mdWxsX2RhdGEgPSBmcm9udGllciAlPiUgZHBseXI6OmlubmVyX2pvaW4ocGFyYW1zX3NkX21lYW5fcmV3YXJkX29yZGVyZWQsIGJ5PWMoJ2RpZmZfc2QnLCAnbWVhbl9kaWZmX3BlcmMnKSkgJT4lZHBseXI6OiBpbm5lcl9qb2luKHBhcmFtc19tb3JlX3RoYW5fMTBfcGVyYywgYnk9YygiaW5kaXZpZHVhbF9jIiwgImluZGl2aWR1YWxfbSIpKSAlPiUgZHBseXI6Om11dGF0ZSh0eXBlPXBhc3RlKG1lYW5fZGlmZl9wZXJjLGRpZmZfc2QpKQoKCnJiaW5kKGZpbHRlcihzZWxlY3QoZnJvbnRpZXJfZnVsbF9kYXRhLCAia2V5IiwgInR5cGUiLCAidmFsdWUiLCAndmFsdWVfcGVyYycpKSwgc2VsZWN0KGFjdHVhbF9taXhfMjAxOF9yZWR1Y2VkLCAtWDEsIC15ZWFyKSkgJT4lIGdncGxvdChhZXMoeD1rZXksIHk9dmFsdWVfcGVyYywgZmlsbD10eXBlKSkgKyBzdGF0X3N1bW1hcnkoZ2VvbSA9ICJiYXIiLCBmdW4ueSA9IG1lYW4sIHBvc2l0aW9uID0gImRvZGdlMiIpKyBzdGF0X3N1bW1hcnkoZ2VvbSA9ICJlcnJvcmJhciIsIGZ1bi5kYXRhID0gbWVhbl9zZSwgcG9zaXRpb24gPSAiZG9kZ2UyIikgKyBnZ3RpdGxlKCJCZXN0IHBhcmFtZXRlciBjb21iaW5hdGlvbnMgZnJvbSBhbGwgZ2VuZXRpYyBhbGdvcml0aG0gcnVucyIpCiAgICAKYGBgCgpgYGB7cn0KYmVzdF9vbmUgPSBkcGx5cjo6c2VsZWN0KGRwbHlyOjpmaWx0ZXIoZnJvbnRpZXJfZnVsbF9kYXRhLCBtZWFuX2RpZmZfcGVyYzwwLjA2NyksICJrZXkiLCAidHlwZSIsICJ2YWx1ZSIsICd2YWx1ZV9wZXJjJykKYmVzdF9vbmUkdHlwZSA9ICJTaW11bGF0ZWQiCgphY3R1YWxfbWl4XzIwMThfcmVkdWNlZCR0eXBlID0gIkFjdHVhbCIKCnJiaW5kKGJlc3Rfb25lLCBzZWxlY3QoYWN0dWFsX21peF8yMDE4X3JlZHVjZWQsIC1YMSwgLXllYXIpKSAlPiUgZ2dwbG90KGFlcyh4PWtleSwgeT12YWx1ZV9wZXJjLCBmaWxsPXR5cGUpKSArIHN0YXRfc3VtbWFyeShnZW9tID0gImJhciIsIGZ1bi55ID0gbWVhbiwgcG9zaXRpb24gPSAiZG9kZ2UyIikrIHN0YXRfc3VtbWFyeShnZW9tID0gImVycm9yYmFyIiwgZnVuLmRhdGEgPSBtZWFuX3NlLCBwb3NpdGlvbiA9ICJkb2RnZTIiKSArIHRoZW1lX2NsYXNzaWMoKSArdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE4KSkrIHhsYWIoIiIpICsgeWxhYigiRWxlY3RyaWNpdHkgTWl4ICglKSIpICtzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gJ1NldDInKQoKZ2dzYXZlKCJ+L0RvY3VtZW50cy9QaEQvUHJvamVjdHMvMTAtRUxFQ1NJTS9ub3RlYm9va3MvdmFsaWRhdGlvbi1vcHRpbWlzYXRpb24vZmlndXJlcy9pbnRyb2R1Y3Rpb24vYmVzdF9ydW4ucGRmIikKYGBgCgpgYGB7cn0KYmVzdF9hY3R1YWwgPSByYmluZChiZXN0X29uZSwgc2VsZWN0KGFjdHVhbF9taXhfMjAxOF9yZWR1Y2VkLCAtWDEsIC15ZWFyKSkKYmVzdF9hY3R1YWxfc3RhdHMgPSBiZXN0X2FjdHVhbCAlPiUgZHBseXI6Omdyb3VwX2J5KHR5cGUsIGtleSkgJT4lIGRwbHlyOjpzdW1tYXJpc2Uoc2RfdmFsdWUgPSBzZCh2YWx1ZV9wZXJjKSwgbWVhbl92YWx1ZSA9IG1lYW4odmFsdWVfcGVyYykpIAoKYWN0dWFscyA9IGRwbHlyOjpmaWx0ZXIoYmVzdF9hY3R1YWxfc3RhdHMsIHR5cGU9PSJBY3R1YWwiKSRtZWFuX3ZhbHVlCnByZWRpY3RlZCA9IGRwbHlyOjpmaWx0ZXIoYmVzdF9hY3R1YWxfc3RhdHMsIHR5cGU9PSJTaW11bGF0ZWQiKSRtZWFuX3ZhbHVlCgpSTVNFKGFjdHVhbHMscHJlZGljdGVkKQpgYGAKCmBgYHtyfQpwZGNfZXhhbXBsZSRzZWdtZW50X2RlbWFuZCA9IHBkY19leGFtcGxlJHNlZ21lbnRfZGVtYW5kLzEwMDAKCmJlc3RfYyA9IGZpbHRlcihmcm9udGllcl9mdWxsX2RhdGEsIG1lYW5fZGlmZl9wZXJjPDAuMDY3KSRpbmRpdmlkdWFsX2NbMV0KYmVzdF9tID0gZmlsdGVyKGZyb250aWVyX2Z1bGxfZGF0YSwgbWVhbl9kaWZmX3BlcmM8MC4wNjcpJGluZGl2aWR1YWxfbVsxXQoKYmVzdF9wYXJhbXMgJT4lIHRyYW5zZm9ybSh5PWdldF9saW5lKGJlc3RfYywgYmVzdF9tKSwgeD1nZXRfeCgpLzEwMDApICAlPiUgZ2dwbG90KCkgKyBzdGF0X3Ntb290aChkYXRhPXBkY19leGFtcGxlLCBhZXMoeD1zZWdtZW50X2RlbWFuZCwgeT1hY2NlcHRlZF9wcmljZSwgY29sb3I9IlNpbXVsYXRlZCBGaXQgKDIwMTgpIiksIG1ldGhvZD0ibG0iKSArIGdlb21fcG9pbnQoZGF0YT1wZGNfZXhhbXBsZSwgYWVzKHg9c2VnbWVudF9kZW1hbmQsIHk9YWNjZXB0ZWRfcHJpY2UsIGNvbG9yPSJQREMgKDIwMTgpIikpICsgZ2VvbV9saW5lKGFlcyh4PXguMSwgeT14LCBjb2xvcj0iUFBEQyIpLCBzaXplPTIpICsgeGxhYigiRGVtYW5kIChHVykiKSArIHlsYWIoIkFjY2VwdGVkIFByaWNlICjCoy9NV2gpIikgKyBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJEYXRhIiwgIHZhbHVlcyA9IGMoIlBEQyAoMjAxOCkiID0gIm9yYW5nZSIsICJQUERDIiA9ICIjMzA2OTk2IiwgJ1NpbXVsYXRlZCBGaXQgKDIwMTgpJz0ncmVkJykpICArIHRoZW1lX2NsYXNzaWMoKSArdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE4KSkrIHRoZW1lKGFzcGVjdC5yYXRpbyA9IDEsIHBsb3QubWFyZ2luPWdyaWQ6OnVuaXQoYygwLDAsMCwwKSwgIm1tIikpIAoKCmdnc2F2ZSgifi9Eb2N1bWVudHMvUGhEL1Byb2plY3RzLzEwLUVMRUNTSU0vbm90ZWJvb2tzL3ZhbGlkYXRpb24tb3B0aW1pc2F0aW9uL2ZpZ3VyZXMvcmVzdWx0cy9iZXN0X3J1bl9wcmljZV9kdXJfY3VydmUucGRmIiwgZHBpPTEwMDApCmBgYAoKYGBge3J9CnA9Z2dwbG90KHJ1bl8xLCBhZXMoeT1pbmRpdmlkdWFsX20sIHg9aW5kaXZpZHVhbF9jKSkgKyBzdGF0X3N1bW1hcnlfaGV4KGFlcyh6ID0gdGltZV90YWtlbiksIGJpbnM9MTApICsgZmFjZXRfd3JhcCh+IHJ1bl9udW1iZXIpICsgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHJvdW5kKHNlcShtaW4ocnVuXzEkaW5kaXZpZHVhbF9jKSwgbWF4KHJ1bl8xJGluZGl2aWR1YWxfYyksIGJ5ID0gMjUpLDEpKSArIGdndGl0bGUoIkhleGFnb25hbCBoZWF0bWFwIG9mIGlucHV0IHBhcmFtZXRlcnMgYWdhaW5zdCB0aW1lIHRha2VuIHdpdGggcmVzcGVjdCB0byBwb3B1bGF0aW9uIG51bWJlciIpCnAkbGFiZWxzJGZpbGwgPC0gIlRpbWUgXG4gVGFrZW4iCnByaW50KHApCgpnZ3NhdmUoJ34vRGVza3RvcC90aW1lLXRha2VuLXBhcmFtZXRlcnMucG5nJykKYGBgCgpgYGB7cn0KcnVuXzEgJT4lIGFycmFuZ2UoZGVzYyhydW5fbnVtYmVyKSkgJT4lIGdncGxvdChhbHBoYT0wLjEsIGFlcyh5PWluZGl2aWR1YWxfbSwgeD1pbmRpdmlkdWFsX2MpKSArIGdlb21fcG9pbnQoYWVzKGNvbG9yPXJ1bl9udW1iZXIsIHNpemU9dGltZV90YWtlbikpICsgZ2d0aXRsZSgiU2NhdHRlciBwbG90IHNob3dpbmcgcnVuIG51bWJlciBhZ2FpbnN0IHRpbWUgdGFrZW4gYW5kIHJld2FyZCIpCmBgYAoKYGBge3J9CnJ1bl8xICU+JSBmaWx0ZXIoaW5kaXZpZHVhbF9jPC0zLCBpbmRpdmlkdWFsX20gPDAuMDAyNSwgaW5kaXZpZHVhbF9tID4gMC4wMDE1KSAlPiUgZ2dwbG90KGFlcyh4PWFzLmZhY3RvcihydW5fbnVtYmVyKSwgeT10aW1lX3Rha2VuKSkgKyBnZW9tX3Zpb2xpbigpICsgZ2d0aXRsZSgiVmlvbGluIHBsb3Qgb2YgdGltZSB0YWtlbiBmb3IgZWFjaCBzaW11bGF0aW9uIHJ1biBhZ2FpbnN0IHBvcHVsYXRpb24gbnVtYmVyIikKYGBgCmBgYHtyfQpnZ3Bsb3QoZGF0YT1ydW5fMSwgYWVzKHg9YXMuZmFjdG9yKHJ1bl9udW1iZXIpLCB5PXJld2FyZCkpK2dlb21fYm94cGxvdCgpK2dlb21faml0dGVyKHBvc2l0aW9uPXBvc2l0aW9uX2ppdHRlcigwLjIpLCBhbHBoYT0wLjUsIGNvbG9yPSdibHVlJykgKyBnZ3RpdGxlKCJCb3hwbG90IGFuZCBqaXR0ZXIgb2YgcnVuIG51bWJlciBhZ2FpbnN0IHJld2FyZCIpCmBgYAoKCmBgYHtyfQpydW5fMSAlPiUgZmlsdGVyKGluZGl2aWR1YWxfYzwtMywgaW5kaXZpZHVhbF9tIDwwLjAwMjUsIGluZGl2aWR1YWxfbSA+IDAuMDAxNSkgJT4lIGdncGxvdChhZXMoeD1hcy5mYWN0b3IocnVuX251bWJlciksIHk9cmV3YXJkKSkgKyBnZW9tX3Zpb2xpbigpICsgZ2d0aXRsZSgiVmlvbGluIHBsb3Qgb2YgcmV3YXJkIGFnYWluc3QgcG9wdWxhdGlvbiBudW1iZXIiKQoKYGBgCgpgYGB7cn0KZ2dwbG90KHJ1bl8xLCBhZXMoeD1yZXdhcmQsIHk9dGltZV90YWtlbikpK3N0YXRfc21vb3RoKG1ldGhvZCA9ICJsbSIpK2dlb21fcG9pbnQoKSt4bGFiKCJBYnNvbHV0ZSBQZXJjZW50YWdlIEVycm9yIikgKyBnZ3RpdGxlKCJTY2F0dGVyIHBsb3Qgb2YgdGltZSB0YWtlbiBmb3IgZWFjaCBzaW11bGF0aW9uIHJ1biBhZ2FpbnN0IFxuYWJzb2x1dGUgcGVyY2VudGFnZSBlcnJvciIpCgpgYGAKCmBgYHtyfQpkaWZfc3VtID0gcnVuXzFfbG9uZyAlPiUgaW5uZXJfam9pbihhY3R1YWxfbWl4XzIwMThfcmVkdWNlZCwgYnk9J2tleScpICU+JSBncm91cF9ieShpZCxrZXkpICU+JSBtdXRhdGUodG90YWxfZGlmZmVyZW5jZSA9IHZhbHVlLngtdmFsdWUueSkgJT4lIGRkcGx5KC4oaWQsIGtleSksIHN1bW1hcmlzZSwgZGlmZmVyZW5jZV9zdW0gPSBzdW0odG90YWxfZGlmZmVyZW5jZSksIHRpbWVfdGFrZW49dGltZV90YWtlbiwgcmV3YXJkPXJld2FyZCwgcnVuX251bWJlcj1ydW5fbnVtYmVyKSAlPiUgZ3JvdXBfYnkoaWQpICU+JSBzdW1tYXJpc2UodG90X2RpZmYgPSBzdW0oZGlmZmVyZW5jZV9zdW0pLCB0aW1lX3Rha2VuPW1lYW4odGltZV90YWtlbiksIHJld2FyZD1tZWFuKHJld2FyZCksIHJ1bl9udW1iZXI9bWVhbihydW5fbnVtYmVyKSkKCnBsb3RfbHkoZGF0YT1kaWZfc3VtLCB4PX50b3RfZGlmZiwgeT1+dGltZV90YWtlbiwgej1+cmV3YXJkLCB0eXBlPSJzY2F0dGVyM2QiLCBtb2RlPSJtYXJrZXJzIiwgY29sb3I9fnJ1bl9udW1iZXIpIApgYGAKCmBgYHtyfQpnZ3Bsb3QoKStnZW9tX3BvaW50KGRhdGE9cnVuXzEsIGFlcyh4PXRpbWVfdGFrZW4sIHk9cmV3YXJkLCBjb2xvcj1ydW5fbnVtYmVyKSkgKyBnZ3RpdGxlKCJTY2F0dGVyIHBsb3Qgb2YgdGltZSB0YWtlbiBhZ2FpbnN0IHJld2FyZCIpCmBgYAoKYGBge3J9CnJ1bl8xCgpydW5fMV9sb25nID0gZ2F0aGVyKHJ1bl8xLCAia2V5IiwgInZhbHVlIiwgImNvYWwiLCAiY2NndCIsICJ3aW5kIiwgIm51Y2xlYXIiLCAic29sYXIiKQoKIyBydW5fMV9sb25nICU+JSBpbm5lcl9qb2luKGFjdHVhbF9taXhfMjAxOF9yZWR1Y2VkLCBieT0na2V5JykgJT4lIGdyb3VwX2J5KGlkLGtleSkgJT4lIG11dGF0ZSh0b3RhbF9kaWZmZXJlbmNlID0gdmFsdWUueC12YWx1ZS55KSAlPiUgZ3JvdXBfYnkoaWQsIGtleSkgJT4lIHN1bW1hcmlzZShkaWZmZXJlbmNlX3N1bSA9IHN1bSh0b3RhbF9kaWZmZXJlbmNlKSkKCmdncGxvdChkYXRhPWRpZl9zdW0sIGFlcyh4PXRvdF9kaWZmLCB5PXRpbWVfdGFrZW4sIGNvbG9yPXJld2FyZCkpICsgZ2VvbV9wb2ludCgpK2dlb21fc21vb3RoKCkreGxpbSgtMTEwMDAsMTAwMDApCgojIGFjdHVhbF9taXhfMjAxOF9yZWR1Y2VkCmBgYApgYGB7cn0KZ2dwbG90KGRhdGE9ZGlmX3N1bSwgYWVzKHg9dG90X2RpZmYsIGNvbG9yPXRpbWVfdGFrZW4sIHk9cmV3YXJkKSkgKyBnZW9tX3BvaW50KCkrZ2VvbV9zbW9vdGgoKSt4bGltKC0xMTAwMCwxMDAwMCkKYGBgCgpgYGB7cn0KZ2dwbG90KHJ1bl8xLCBhZXMoeD1ydW5fbnVtYmVyLCB5PXRpbWVfdGFrZW4sIGNvbG9yPXJld2FyZCkpICsgZ2VvbV9wb2ludCgpICsKICAgZ2VvbV9zbW9vdGgobWV0aG9kPSdsbScpCmBgYA==
=======
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKCmBgYHtyfQpsaWJyYXJ5KCJ0aWR5dmVyc2UiKQpsaWJyYXJ5KCJnZ3Bsb3QyIikKbGlicmFyeShwbHlyKQpsaWJyYXJ5KCJtY28iKQpgYGAKYGBge3J9CnJ1bl8xID0gcmVhZF9jc3YoJy9Vc2Vycy9iMTAxNzU3OS9Eb2N1bWVudHMvUGhEL1Byb2plY3RzLzEwLUVMRUNTSU0vcnVuL3ZhbGlkYXRpb24tb3B0aW1pc2F0aW9uL2RhdGEvcnVuXzIuY3N2JykKdGFpbChydW5fMSkKYGBgCmBgYHtyfQpnZ3Bsb3QoZmlsdGVyKHJ1bl8xKSwgYWVzKHk9aW5kaXZpZHVhbF9tLCB4PWluZGl2aWR1YWxfYykpICsgZ2VvbV9oZXgoYmlucz0xMCkKYGBgCgpgYGB7cn0KcCA9IGdncGxvdChydW5fMSwgYWVzKHk9aW5kaXZpZHVhbF9tLCB4PWluZGl2aWR1YWxfYywgY29sb3I9cmV3YXJkKSwgc2l6ZT0xMCkgKyBmYWNldF93cmFwKH5ydW5fbnVtYmVyKSArIGdlb21fcG9pbnQoKSArIGdndGl0bGUoIlNjYXR0ZXIgcGxvdCBvZiBpbnB1dCBwYXJhbWV0ZXJzIGFuZCByZXdhcmQiKQpwJGxhYmVscyRmaWxsIDwtICJBYnNvbHV0ZSBcblBlcmNlbnRhZ2UgXG5FcnJvciIKcHJpbnQocCkKYGBgCmBgYHtyfQpwID0gZ2dwbG90KHJ1bl8xLCBhZXMoeT1pbmRpdmlkdWFsX20sIHg9aW5kaXZpZHVhbF9jLCBjb2xvcj1yZXdhcmQpLCBzaXplPTEwKSArIGZhY2V0X3dyYXAofnJ1bl9udW1iZXIpICsgZ2VvbV9qaXR0ZXIoKSArIGdndGl0bGUoIlNjYXR0ZXIgKGppdHRlcikgcGxvdCBvZiBpbnB1dCBwYXJhbWV0ZXJzIGFuZCByZXdhcmQiKQpwJGxhYmVscyRmaWxsIDwtICJBYnNvbHV0ZSBcblBlcmNlbnRhZ2UgXG5FcnJvciIKcHJpbnQocCkKYGBgCgoKYGBge3J9CnAgPSBnZ3Bsb3QocnVuXzEsIGFlcyh5PWluZGl2aWR1YWxfbSwgeD1pbmRpdmlkdWFsX2MsIGNvbG9yPXRpbWVfdGFrZW4pLCBzaXplPTEwKSArIGZhY2V0X3dyYXAofnJ1bl9udW1iZXIpICsgZ2VvbV9qaXR0ZXIoKSArIGdndGl0bGUoIlNjYXR0ZXIgcGxvdCBvZiBpbnB1dCBwYXJhbWV0ZXJzIGFuZCB0aW1lIHRha2VuIikKcCRsYWJlbHMkZmlsbCA8LSAiVGltZSBcblRha2VuIgpwcmludChwKQoKYGBgCgpgYGB7cn0KcD1nZ3Bsb3QocnVuXzEsIGFlcyh5PWluZGl2aWR1YWxfbSwgeD1pbmRpdmlkdWFsX2MpKSArIHN0YXRfc3VtbWFyeV9oZXgoYWVzKHogPSByZXdhcmQpLCBiaW5zPTEwKSArIGZhY2V0X3dyYXAofiBydW5fbnVtYmVyKSArIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSByb3VuZChzZXEobWluKHJ1bl8xJGluZGl2aWR1YWxfYyksIG1heChydW5fMSRpbmRpdmlkdWFsX2MpLCBieSA9IDI1KSwxKSkgKyBnZ3RpdGxlKCJIZXhhZ29uYWwgaGVhdG1hcCBvZiBpbnB1dCBwYXJhbWV0ZXJzIGFuZCBBYnNvbHV0ZSBQZXJjZW50YWdlIEVycm9yIikKcCRsYWJlbHMkZmlsbCA8LSAiQWJzb2x1dGUgXG5QZXJjZW50YWdlIFxuRXJyb3IiCnByaW50KHApCgpnZ3NhdmUoIn4vRGVza3RvcC9nZW5ldGljX2FsZ29yaXRobV9wcm9ncmVzc2lvbi5wbmciKQpgYGAKCmBgYHtyfQpydW5fMSAlPiUgZHBseXI6Omdyb3VwX2J5KHJ1bl9udW1iZXIpICU+JSBkcGx5cjo6c3VtbWFyaXNlKGF2Z19yZXdhcmQgPSBtZWFuKHJld2FyZCkpICU+JSBnZ3Bsb3QoKSsgZ2VvbV9zbW9vdGgoZGF0YT1ydW5fMSwgYWVzKHg9cnVuX251bWJlciwgcmV3YXJkKSkrZ2VvbV9saW5lKGFlcyh4PXJ1bl9udW1iZXIsIHk9YXZnX3Jld2FyZCkpK2dndGl0bGUoIkF2ZXJhZ2UgcmV3YXJkIHZzIFBvcHVsYXRpb24gTnVtYmVyIikgCmBgYAoKCgoKCmBgYHtyfQojIGFjY3VyYXRlX2FyZWEgPSBmaWx0ZXIocnVuXzEsIGluZGl2aWR1YWxfYzwtNC44LCBpbmRpdmlkdWFsX2M+LTUwLCBpbmRpdmlkdWFsX20gPDAuMDAzLCBpbmRpdmlkdWFsX20gPiAwLjAwMjMpCiMgYWNjdXJhdGVfYXJlYSA9IGZpbHRlcihydW5fMSwgcmV3YXJkIDwgMC4yKQojIGFjY3VyYXRlX2FyZWEgPSBmaWx0ZXIocnVuXzEsIHJ1bl9udW1iZXI9PTExKQphY2N1cmF0ZV9hcmVhID0gZmlsdGVyKHJ1bl8xLCBydW5fbnVtYmVyID09IDE2KQoKYWNjdXJhdGVfYXJlYQoKYGBgCgpgYGB7cn0KIGdncGxvdChkYXRhPWFjY3VyYXRlX2FyZWEsIGFlcyh4PWluZGl2aWR1YWxfYywgeT1pbmRpdmlkdWFsX20sIGNvbG9yPXJld2FyZCkpK2dlb21faml0dGVyKCkrZ2VvbV9wb2ludChjb2xvcj0icmVkIiwgYWxwaGE9MC41KSArIGdndGl0bGUoIlNjYXR0ZXIgYW5kIEppdHRlcnBsb3Qgb2YgUmV3YXJkIGFnYWluc3QgSW5wdXQgUGFyYW1ldGVycyBmb3IgXG5MYXN0IFBvcHVsYXRpb24gb2YgR0EiKQoKYGBgCgoKYGBge3J9CmFjY3VyYXRlX2FyZWFfbG9uZyA9IGdhdGhlcihhY2N1cmF0ZV9hcmVhLCAia2V5IiwgInZhbHVlIiwgImNvYWwiLCAiY2NndCIsICJ3aW5kIiwgIm51Y2xlYXIiLCAic29sYXIiKQphY2N1cmF0ZV9hcmVhX2xvbmdfcGVyYyA9IGFjY3VyYXRlX2FyZWFfbG9uZyAlPiUgZ3JvdXBfYnkoaWQpICU+JSBtdXRhdGUodmFsdWVfcGVyYyA9IHZhbHVlL3N1bSh2YWx1ZSkpCgpgYGAKCgpgYGB7cn0KcGFyYW1zX21vcmVfdGhhbl8xMCA9IHJ1bl8xICU+JSBncm91cF9ieShpbmRpdmlkdWFsX2MsIGluZGl2aWR1YWxfbSkgJT4lIGRwbHlyOjptdXRhdGUobnVtYmVyID0gbigpKSAlPiUgdW5ncm91cCgpICU+JSBmaWx0ZXIobnVtYmVyPiAxMCkgJT4lIGRwbHlyOjptdXRhdGVfaWYoaXMubnVtZXJpYywgcm91bmQsIDYpIAoKcGFyYW1zX21vcmVfdGhhbl8xMCAlPiUgZ2dwbG90KGFlcyhhcy5mYWN0b3IoaW5kaXZpZHVhbF9jKSwgcmV3YXJkKSkgK2dlb21fdmlvbGluKCkrZmFjZXRfd3JhcCh+aW5kaXZpZHVhbF9tKSsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkgK2dlb21faml0dGVyKHBvc2l0aW9uPXBvc2l0aW9uX2ppdHRlcigwLjIpLCBhbHBoYT0wLjA1KSArIGdndGl0bGUoIlZpb2xpbiBwbG90IG9mIGlucHV0IHBhcmFtZXRlcnMgd2l0aCBtb3JlIHRoYW4gMTAgc2ltdWxhdGlvbnMgXG5hZ2FpbnN0IGRpc3RyaWJ1dGlvbiBvZiByZXdhcmQiKQoKYGBgCgpgYGB7cn0KYWNjdXJhdGVfYXJlYSAlPiUgbXV0YXRlX2lmKGlzLm51bWVyaWMsIHJvdW5kLCA2KSAlPiUgZ2dwbG90KGFlcyhhcy5mYWN0b3IoaW5kaXZpZHVhbF9jKSwgcmV3YXJkKSkgK2dlb21fdmlvbGluKCkrZmFjZXRfd3JhcCh+aW5kaXZpZHVhbF9tKSsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkgK2dlb21faml0dGVyKHBvc2l0aW9uPXBvc2l0aW9uX2ppdHRlcigwLjIpKSsgZ2d0aXRsZSgiVmlvbGluIHBsb3Qgb2YgaW5wdXQgcGFyYW1ldGVycyB3aXRoIG1vcmUgdGhhbiAxMCBzaW11bGF0aW9ucyBvZiBsYXN0IHBvcHVsYXRpb24gb2YgR0FcbmFnYWluc3QgZGlzdHJpYnV0aW9uIG9mIHJld2FyZCIpCgpgYGAKCgpgYGB7cn0KYWN0dWFsX21peCA9IHJlYWRfY3N2KCcvVXNlcnMvYjEwMTc1NzkvRG9jdW1lbnRzL1BoRC9Qcm9qZWN0cy8xMC1FTEVDU0lNL2VsZWNzaW0vZGF0YS9wcm9jZXNzZWQvZWxlY3RyaWNpdHlfbWl4L2VuZXJneV9taXhfaGlzdG9yaWNhbC5jc3YnKQphY3R1YWxfbWl4XzIwMTggPSBmaWx0ZXIoYWN0dWFsX21peCwgeWVhcj09MjAxOCkKCgphY3R1YWxfbWl4XzIwMTgkdHlwZSA9ICJhY3R1YWwiCgphY3R1YWxfbWl4XzIwMTgKYGBgCgpgYGB7cn0KYWN0dWFsX21peF8yMDE4X3JlZHVjZWQgPSBmaWx0ZXIoYWN0dWFsX21peF8yMDE4LCB2YXJpYWJsZSAlaW4lIGMoImNjZ3QiLCAnd2luZCcsICdudWNsZWFyJywgJ3NvbGFyJywgJ2NvYWwnKSkKYWN0dWFsX21peF8yMDE4X3JlZHVjZWQgPSBhY3R1YWxfbWl4XzIwMThfcmVkdWNlZCAlPiUgbXV0YXRlKHZhbHVlX3BlcmMgPSB2YWx1ZS9zdW0odmFsdWUpKQphY3R1YWxfbWl4XzIwMThfcmVkdWNlZCA9IGRwbHlyOjpyZW5hbWUoYWN0dWFsX21peF8yMDE4X3JlZHVjZWQsIGtleT12YXJpYWJsZSkKaGVhZChhY3R1YWxfbWl4XzIwMThfcmVkdWNlZCkKYGBgCmBgYHtyfQphY2N1cmF0ZV9hcmVhX2xvbmdfcGVyYyR0eXBlID0gJ3ByZWRpY3RlZCcKYWNjdXJhdGVfYXJlYV9sb25nX3BlcmMKCmNvbXBhcmlzb24gPSByYmluZChzZWxlY3QodW5ncm91cChhY2N1cmF0ZV9hcmVhX2xvbmdfcGVyYyksICJrZXkiLCAidHlwZSIsICJ2YWx1ZSIsICd2YWx1ZV9wZXJjJyksIHNlbGVjdChhY3R1YWxfbWl4XzIwMThfcmVkdWNlZCwgLVgxLCAteWVhcikpCmBgYAoKCgoKCmBgYHtyfQpnZ3Bsb3QoY29tcGFyaXNvbiwgYWVzKHg9a2V5LCB5PXZhbHVlX3BlcmMsIGZpbGw9dHlwZSkpICsKICBzdGF0X3N1bW1hcnkoZ2VvbSA9ICJiYXIiLCBmdW4ueSA9IG1lYW4sIHBvc2l0aW9uID0gImRvZGdlMiIpKyBzdGF0X3N1bW1hcnkoZ2VvbSA9ICJlcnJvcmJhciIsIGZ1bi5kYXRhID0gbWVhbl9zZSwgcG9zaXRpb24gPSAiZG9kZ2UyIikgKyB5bGFiKCJFbmVyZ3kgTWl4ICglKSIpICsgZ2d0aXRsZSgiQ29tYmluYXRpb24gb2YgYWxsIHJ1bnMgaW4gbGFzdCBnZW5ldGljIGFsZ29yaXRobSBydW4iKQoKZ2dzYXZlKCd+L0Rlc2t0b3AvYXZlcmFnZV9lcnJvcl9vZl9iZXN0X3BhcmFtcy5wbmcnKQpgYGAKCmBgYHtyfQpiZXN0X3Jlc3VsdCA9IHJ1bl8xICU+JSBncm91cF9ieSgiaWQiKSAlPiUgZmlsdGVyKHJld2FyZD09bWluKHJld2FyZCkpICU+JSBnYXRoZXIoImtleSIsICJ2YWx1ZSIsICJjb2FsIiwgImNjZ3QiLCAid2luZCIsICJudWNsZWFyIiwgInNvbGFyIikgJT4lIGdyb3VwX2J5KGlkKSAlPiUgbXV0YXRlKHZhbHVlX3BlcmMgPSB2YWx1ZS9zdW0odmFsdWUpKSAlPiUgbXV0YXRlKHR5cGU9InByZWRpY3RlZCIpCgpjb21wYXJpc29uX2Jlc3QgPSByYmluZChzZWxlY3QodW5ncm91cChiZXN0X3Jlc3VsdCksICJrZXkiLCAidHlwZSIsICJ2YWx1ZSIsICd2YWx1ZV9wZXJjJyksIHNlbGVjdChhY3R1YWxfbWl4XzIwMThfcmVkdWNlZCwgLVgxLCAteWVhcikpCgpnZ3Bsb3QoY29tcGFyaXNvbl9iZXN0LCBhZXMoeD1rZXksIHk9dmFsdWVfcGVyYywgZmlsbD10eXBlKSkgKyBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZTIiKSArIHlsYWIoIkVuZXJneSBNaXggKCUpIikgKyBnZ3RpdGxlKCJCZXN0IHNpbmdsZSBydW4iKQpgYGAKCgpgYGB7cn0KcGRjX2V4YW1wbGUgPSByZWFkX2NzdignL1VzZXJzL2IxMDE3NTc5L0RvY3VtZW50cy9QaEQvUHJvamVjdHMvMTAtRUxFQ1NJTS9ub3RlYm9va3MvdmFsaWRhdGlvbi1vcHRpbWlzYXRpb24vZGF0YS9wcmljZV9kZW1hbmRfY3VydmVfZXhhbXBsZS5jc3YnKQoKCmRlbWFuZF9yYW5nZSA9IGRhdGEuZnJhbWUoeD1zZXEoZnJvbT1taW4ocGRjX2V4YW1wbGUkc2VnbWVudF9kZW1hbmQpLG1heChwZGNfZXhhbXBsZSRzZWdtZW50X2RlbWFuZCksbGVuZ3RoLm91dD01MDApKQoKZ2V0X2xpbmUgPSBmdW5jdGlvbihjLCBtKXsKICAgIHkgPSBtICogZGVtYW5kX3JhbmdlICsgYwogICAgcmV0dXJuKHkpCn0KCmdldF94ID0gZnVuY3Rpb24oKXsKICAgIHJldHVybihkZW1hbmRfcmFuZ2UpCn0KCiMgbGluZXMgPSBhY2N1cmF0ZV9hcmVhICU+JSBncm91cF9ieShpZCkgJT4lIGFwcGx5KGdldF9saW5lKC4pKQoKbGluZXMgPSBkZHBseShhY2N1cmF0ZV9hcmVhLCAuKGlkKSwgdHJhbnNmb3JtLCB5PWdldF9saW5lKGluZGl2aWR1YWxfYywgaW5kaXZpZHVhbF9tKSwgeD1nZXRfeCgpKQoKCmdncGxvdCgpICsgZ2VvbV9saW5lKGRhdGE9bGluZXMsIGFlcyh4PXguMSwgeT14LCBncm91cD1pZCwgY29sb3I9cmV3YXJkKSkgKyBzdGF0X3Ntb290aChkYXRhPXBkY19leGFtcGxlLCBhZXMoeD1zZWdtZW50X2RlbWFuZCwgeT1hY2NlcHRlZF9wcmljZSksIG1ldGhvZD0ibG0iLCBjb2w9InJlZCIpICsgZ2VvbV9wb2ludChkYXRhPXBkY19leGFtcGxlLCBhZXMoeD1zZWdtZW50X2RlbWFuZCwgeT1hY2NlcHRlZF9wcmljZSkpICsgeGxhYigiRGVtYW5kIChNVykiKSArIHlsYWIoIkFjY2VwdGVkIFByaWNlIikgKyBnZ3RpdGxlKCJMYXN0IGdlbmV0aWMgYWxnb3JpdGhtIHJ1biBwcmljZSBjdXJ2ZXMgYmV0d2VlbiAyMDIzLTIwMjggXG5jb21wYXJlZCB0byBwcmljZSBpbiAyMDE4IikKCmBgYAoKYGBge3J9CmJlc3RfNzVfcGVyY2VudGlsZSA9IGFjY3VyYXRlX2FyZWEgJT4lIGdyb3VwX2J5KGluZGl2aWR1YWxfYywgaW5kaXZpZHVhbF9tKSAlPiUgZHBseXI6OnN1bW1hcmlzZShudW1iZXI9bigpLCBxdWFudGlsZXMgPSBsaXN0KGVuZnJhbWUocXVhbnRpbGUocmV3YXJkLCBwcm9icz1jKDAuMjUsMC41LDAuNzUpKSkpKSAlPiUgdW5uZXN0ICU+JSB1bmdyb3VwKCkgJT4lIGZpbHRlcihudW1iZXI+MTApICU+JSBncm91cF9ieShuYW1lKSAlPiVmaWx0ZXIocmFuayh2YWx1ZSwgdGllcy5tZXRob2Q9ImZpcnN0Iik9PTEpCgpwID0gZGRwbHkoYmVzdF83NV9wZXJjZW50aWxlLCAuKG5hbWUpLCB0cmFuc2Zvcm0sIHk9Z2V0X2xpbmUoaW5kaXZpZHVhbF9jLCBpbmRpdmlkdWFsX20pLCB4PWdldF94KCkpICAlPiUgZ2dwbG90KCkgKyBnZW9tX2xpbmUoYWVzKHg9eC4xLCB5PXgsIGNvbG9yPW5hbWUpKSsgc3RhdF9zbW9vdGgoZGF0YT1wZGNfZXhhbXBsZSwgYWVzKHg9c2VnbWVudF9kZW1hbmQsIHk9YWNjZXB0ZWRfcHJpY2UpLCBtZXRob2Q9ImxtIiwgY29sPSJ5ZWxsb3ciKSArIGdlb21fcG9pbnQoZGF0YT1wZGNfZXhhbXBsZSwgYWVzKHg9c2VnbWVudF9kZW1hbmQsIHk9YWNjZXB0ZWRfcHJpY2UpKSArIHhsYWIoIkRlbWFuZCAoTVcpIikgKyB5bGFiKCJBY2NlcHRlZCBQcmljZSIpICsgZ2d0aXRsZSgiUHJpY2UgY3VydmUgb2YgYmVzdCBydW5zIGF0IGRpZmZlcmVudCBwZXJjZW50aWxlcyBvZiBsYXN0IGdlbmV0aWMgXG5hbGdvcml0aG0gcG9wdWxhdGlvbiIpCnAkbGFiZWxzJGZpbGwgPC0gIlBlcmNlbnRpbGVzIgpwcmludChwKQpgYGAKYGBge3J9CmJlc3RfcGVyY2VudGlsZXNfY29tcGFyaXNvbiA9IGlubmVyX2pvaW4oYWNjdXJhdGVfYXJlYSwgYmVzdF83NV9wZXJjZW50aWxlLCBieT1jKCdpbmRpdmlkdWFsX2MnLCAnaW5kaXZpZHVhbF9tJykpICU+JSBnYXRoZXIoImtleSIsICJ2YWx1ZSIsICJjb2FsIiwgImNjZ3QiLCAid2luZCIsICJudWNsZWFyIiwgInNvbGFyIikgJT4lIGdyb3VwX2J5KGlkKSAlPiUgbXV0YXRlKHZhbHVlX3BlcmMgPSB2YWx1ZS9zdW0odmFsdWUpKSAlPiUgbXV0YXRlKHR5cGU9bmFtZSkKCmNvbXBhcmlzb25fcGVyY2VudGlsZXMgPSByYmluZChzZWxlY3QodW5ncm91cChiZXN0X3BlcmNlbnRpbGVzX2NvbXBhcmlzb24pLCAia2V5IiwgInR5cGUiLCAidmFsdWUiLCAndmFsdWVfcGVyYycpLCBzZWxlY3QoYWN0dWFsX21peF8yMDE4X3JlZHVjZWQsIC1YMSwgLXllYXIpKQoKY29tcGFyaXNvbl9wZXJjZW50aWxlcyAlPiUgZ2dwbG90KGFlcyh4PWtleSwgeT12YWx1ZV9wZXJjLCBmaWxsPXR5cGUpKSArIHN0YXRfc3VtbWFyeShnZW9tID0gImJhciIsIGZ1bi55ID0gbWVhbiwgcG9zaXRpb24gPSAiZG9kZ2UyIikrIHN0YXRfc3VtbWFyeShnZW9tID0gImVycm9yYmFyIiwgZnVuLmRhdGEgPSBtZWFuX3NlLCBwb3NpdGlvbiA9ICJkb2RnZTIiKSArIGdndGl0bGUoIkNvbXBhcmlzb24gb2YgZW5lcmd5IG1peCBvZiBmaW5hbCBnZW5ldGljIGFsZ29yaXRobSBwb3B1bGF0aW9uIFxuYXQgZGlmZmVyZW50IHF1YW50aWxlIGxldmVscyIpCgoKYGBgCmBgYHtyfQpyYmluZChmaWx0ZXIoc2VsZWN0KHVuZ3JvdXAoYmVzdF9wZXJjZW50aWxlc19jb21wYXJpc29uKSwgImtleSIsICJ0eXBlIiwgInZhbHVlIiwgJ3ZhbHVlX3BlcmMnKSx0eXBlPT0iNTAlIiksIHNlbGVjdChhY3R1YWxfbWl4XzIwMThfcmVkdWNlZCwgLVgxLCAteWVhcikpICU+JSBnZ3Bsb3QoYWVzKHg9a2V5LCB5PXZhbHVlX3BlcmMsIGZpbGw9dHlwZSkpICsgc3RhdF9zdW1tYXJ5KGdlb20gPSAiYmFyIiwgZnVuLnkgPSBtZWFuLCBwb3NpdGlvbiA9ICJkb2RnZTIiKSsgc3RhdF9zdW1tYXJ5KGdlb20gPSAiZXJyb3JiYXIiLCBmdW4uZGF0YSA9IG1lYW5fc2UsIHBvc2l0aW9uID0gImRvZGdlMiIpICsgZ2d0aXRsZSgiQmVzdCBwYXJhbWV0ZXIgY29tYmluYXRpb25zIGZyb20gZmluYWwgZ2VuZXRpYyBhbGdvcml0aG0gcnVuIikKCmBgYAoKCiMjIEJFU1QgUEFSQU1FVEVSIENPTUJJTkFUSU9OIEZST00gQUxMIFJVTlMKCmBgYHtyfQpiZXN0Xzc1X3BlcmNlbnRpbGVfYWxsX3J1bnMgPSBydW5fMSAlPiUgZ3JvdXBfYnkoaW5kaXZpZHVhbF9jLCBpbmRpdmlkdWFsX20pICU+JSBkcGx5cjo6c3VtbWFyaXNlKG51bWJlcj1uKCksIHF1YW50aWxlcyA9IGxpc3QoZW5mcmFtZShxdWFudGlsZShyZXdhcmQsIHByb2JzPWMoMC4yNSwwLjUsMC43NSwgMC45LCAxLjApKSkpKSAlPiUgdW5uZXN0ICU+JSB1bmdyb3VwKCkgJT4lIGZpbHRlcihudW1iZXI+MTApICU+JSBncm91cF9ieShuYW1lKSAlPiVmaWx0ZXIocmFuayh2YWx1ZSwgdGllcy5tZXRob2Q9ImZpcnN0Iik9PTEpCgpwID0gZGRwbHkoYmVzdF83NV9wZXJjZW50aWxlX2FsbF9ydW5zLCAuKG5hbWUpLCB0cmFuc2Zvcm0sIHk9Z2V0X2xpbmUoaW5kaXZpZHVhbF9jLCBpbmRpdmlkdWFsX20pLCB4PWdldF94KCkpICAlPiUgZ2dwbG90KCkgKyBnZW9tX2xpbmUoYWVzKHg9eC4xLCB5PXgsIGNvbG9yPW5hbWUpKSsgc3RhdF9zbW9vdGgoZGF0YT1wZGNfZXhhbXBsZSwgYWVzKHg9c2VnbWVudF9kZW1hbmQsIHk9YWNjZXB0ZWRfcHJpY2UpLCBtZXRob2Q9ImxtIiwgY29sPSJ5ZWxsb3ciKSArIGdlb21fcG9pbnQoZGF0YT1wZGNfZXhhbXBsZSwgYWVzKHg9c2VnbWVudF9kZW1hbmQsIHk9YWNjZXB0ZWRfcHJpY2UpKSArIHhsYWIoIkRlbWFuZCAoTVcpIikgKyB5bGFiKCJBY2NlcHRlZCBQcmljZSIpICsgZ2d0aXRsZSgiUGVyY2VudGlsZXMgZnJvbSBhbGwgcnVucyIpCnAkbGFiZWxzJGZpbGwgPC0gIlBlcmNlbnRpbGVzIgpwcmludChwKQpgYGAKYGBge3J9CmJlc3RfcGVyY2VudGlsZXNfY29tcGFyaXNvbiA9IGlubmVyX2pvaW4ocnVuXzEsIGJlc3RfNzVfcGVyY2VudGlsZV9hbGxfcnVucywgYnk9YygnaW5kaXZpZHVhbF9jJywgJ2luZGl2aWR1YWxfbScpKSAlPiUgZ2F0aGVyKCJrZXkiLCAidmFsdWUiLCAiY29hbCIsICJjY2d0IiwgIndpbmQiLCAibnVjbGVhciIsICJzb2xhciIpICU+JSBncm91cF9ieShpZCkgJT4lIG11dGF0ZSh2YWx1ZV9wZXJjID0gdmFsdWUvc3VtKHZhbHVlKSkgJT4lIG11dGF0ZSh0eXBlPW5hbWUpCgpjb21wYXJpc29uX3BlcmNlbnRpbGVzID0gcmJpbmQoc2VsZWN0KHVuZ3JvdXAoYmVzdF9wZXJjZW50aWxlc19jb21wYXJpc29uKSwgImtleSIsICJ0eXBlIiwgInZhbHVlIiwgJ3ZhbHVlX3BlcmMnKSwgc2VsZWN0KGFjdHVhbF9taXhfMjAxOF9yZWR1Y2VkLCAtWDEsIC15ZWFyKSkKCmNvbXBhcmlzb25fcGVyY2VudGlsZXMgJT4lIGdncGxvdChhZXMoeD1rZXksIHk9dmFsdWVfcGVyYywgZmlsbD10eXBlKSkgKyBzdGF0X3N1bW1hcnkoZ2VvbSA9ICJiYXIiLCBmdW4ueSA9IG1lYW4sIHBvc2l0aW9uID0gImRvZGdlMiIpKyBzdGF0X3N1bW1hcnkoZ2VvbSA9ICJlcnJvcmJhciIsIGZ1bi5kYXRhID0gbWVhbl9zZSwgcG9zaXRpb24gPSAiZG9kZ2UyIikKYGBgCmBgYHtyfQpyYmluZChmaWx0ZXIoc2VsZWN0KHVuZ3JvdXAoYmVzdF9wZXJjZW50aWxlc19jb21wYXJpc29uKSwgImtleSIsICJ0eXBlIiwgInZhbHVlIiwgJ3ZhbHVlX3BlcmMnKSx0eXBlPT0iNzUlIiB8IHR5cGU9PSI5MCUiKSwgc2VsZWN0KGFjdHVhbF9taXhfMjAxOF9yZWR1Y2VkLCAtWDEsIC15ZWFyKSkgJT4lIGdncGxvdChhZXMoeD1rZXksIHk9dmFsdWVfcGVyYywgZmlsbD10eXBlKSkgKyBzdGF0X3N1bW1hcnkoZ2VvbSA9ICJiYXIiLCBmdW4ueSA9IG1lYW4sIHBvc2l0aW9uID0gImRvZGdlMiIpKyBzdGF0X3N1bW1hcnkoZ2VvbSA9ICJlcnJvcmJhciIsIGZ1bi5kYXRhID0gbWVhbl9zZSwgcG9zaXRpb24gPSAiZG9kZ2UyIikgKyBnZ3RpdGxlKCJCZXN0IHBhcmFtZXRlciBjb21iaW5hdGlvbnMgZnJvbSBhbGwgZ2VuZXRpYyBhbGdvcml0aG0gcnVucyIpCgpgYGAKCiMjIENhbGN1bGF0aW9uIG9mIGJlc3QgcXVhbnRpbGUgdG8gc2VsZWN0IGNvbWJpbmF0aW9uIG9mIHBhcmFtZXRlcnMgZm9yIGxvd2VzdCByZXdhcmQKCmBgYHtyfQpiZXN0X3BhcmFtcyA9IHBhcmFtc19tb3JlX3RoYW5fMTAgJT4lIGdyb3VwX2J5KGluZGl2aWR1YWxfYywgaW5kaXZpZHVhbF9tKSAlPiUgZ2F0aGVyKCJrZXkiLCAidmFsdWUiLCAiY29hbCIsICJjY2d0IiwgIndpbmQiLCAibnVjbGVhciIsICJzb2xhciIpICU+JSBncm91cF9ieShpZCkgJT4lIG11dGF0ZSh2YWx1ZV9wZXJjID0gdmFsdWUvc3VtKHZhbHVlKSkgJT4lIGdyb3VwX2J5KGlkLCBrZXkpICU+JSBpbm5lcl9qb2luKGFjdHVhbF9taXhfMjAxOF9yZWR1Y2VkLCBieT0ia2V5IikgJT4lIG11dGF0ZShkaWZmX3BlcmMgPSBhYnModmFsdWVfcGVyYy54LXZhbHVlX3BlcmMueSkpICU+JSBncm91cF9ieShpZCkgJT4lIHN1bW1hcmlzZShtZWFuX2RpZmZfcGVyYyA9IG1lYW4oZGlmZl9wZXJjKSwgaW5kaXZpZHVhbF9jID0gbWVhbihpbmRpdmlkdWFsX2MpLCBpbmRpdmlkdWFsX20gPSBtZWFuKGluZGl2aWR1YWxfbSkpICU+JSBmaWx0ZXIocmFuayhtZWFuX2RpZmZfcGVyYywgdGllcy5tZXRob2Q9ImZpcnN0Iik9PTEpCgpiZXN0X3BhcmFtc19jb21wYXJpc29uID0gZmlsdGVyKHJ1bl8xLGRwbHlyOjpuZWFyKHg9aW5kaXZpZHVhbF9jLCB5PWJlc3RfcGFyYW1zJGluZGl2aWR1YWxfY1sxXSwgdG9sPTAuMDAwMDEpLGRwbHlyOjpuZWFyKHg9aW5kaXZpZHVhbF9tLCB5PWJlc3RfcGFyYW1zJGluZGl2aWR1YWxfbVsxXSwgdG9sPTAuMDAwMDEpKSAlPiUgZ2F0aGVyKCJrZXkiLCAidmFsdWUiLCAiY29hbCIsICJjY2d0IiwgIndpbmQiLCAibnVjbGVhciIsICJzb2xhciIpICU+JSBkcGx5cjo6Z3JvdXBfYnkoaWQpICU+JSBkcGx5cjo6bXV0YXRlKHZhbHVlX3BlcmMgPSB2YWx1ZS9zdW0odmFsdWUpKSAlPiUgZHBseXI6Om11dGF0ZSh0eXBlPSJwcmVkaWN0ZWQiKQoKY29tcGFyaXNvbl9iZXN0X3BhcmFtcyA9IHJiaW5kKHNlbGVjdCh1bmdyb3VwKGJlc3RfcGFyYW1zX2NvbXBhcmlzb24pLCAia2V5IiwgInR5cGUiLCAidmFsdWUiLCAndmFsdWVfcGVyYycpLCBzZWxlY3QoYWN0dWFsX21peF8yMDE4X3JlZHVjZWQsIC1YMSwgLXllYXIpKQoKY29tcGFyaXNvbl9iZXN0X3BhcmFtcyAlPiUgZ2dwbG90KGFlcyh4PWtleSwgeT12YWx1ZV9wZXJjLCBmaWxsPXR5cGUpKSArIHN0YXRfc3VtbWFyeShnZW9tID0gImJhciIsIGZ1bi55ID0gbWVhbiwgcG9zaXRpb24gPSAiZG9kZ2UyIikrIHN0YXRfc3VtbWFyeShnZW9tID0gImVycm9yYmFyIiwgZnVuLmRhdGEgPSBtZWFuX3NlLCBwb3NpdGlvbiA9ICJkb2RnZTIiKSArIGdndGl0bGUoIkNvbXBhcmlzb24gb2YgcHJlZGljdGVkIHZzIGFjdHVhbCBmb3IgYmVzdCBwYXJhbWV0ZXIgc2V0IG92ZXIgMTAgZnJvbSBhbGwgcnVucyIpCgoKCiMjIEdldHRpbmcgTUFQRSBmb3IgYmVzdCBwYXJhbQoKcHJlZGljdGVkX21lYW5zX2Jlc3RfcGFyYW0gPSBkcGx5cjo6ZmlsdGVyKHJ1bl8xLGRwbHlyOjpuZWFyKHg9aW5kaXZpZHVhbF9jLCB5PWJlc3RfcGFyYW1zJGluZGl2aWR1YWxfY1sxXSwgdG9sPTAuMSksZHBseXI6Om5lYXIoeD1pbmRpdmlkdWFsX20sIHk9YmVzdF9wYXJhbXMkaW5kaXZpZHVhbF9tWzFdLCB0b2w9MC4xKSkgJT4lIGdhdGhlcigia2V5IiwgInZhbHVlIiwgImNvYWwiLCAiY2NndCIsICJ3aW5kIiwgIm51Y2xlYXIiLCAic29sYXIiKSAlPiUgZHBseXI6Omdyb3VwX2J5KGlkKSAlPiUgZHBseXI6Om11dGF0ZSh2YWx1ZV9wZXJjID0gdmFsdWUvc3VtKHZhbHVlKSkgJT4lIGRwbHlyOjptdXRhdGUodHlwZT0icHJlZGljdGVkIikgJT4lIGRwbHlyOjpncm91cF9ieShpbmRpdmlkdWFsX2MsIGluZGl2aWR1YWxfbSwga2V5KSAlPiUgZHBseXI6OnN1bW1hcmlzZShwcmVkaWN0ZWRfcGVyYyA9IG1lYW4odmFsdWVfcGVyYykpIAoKcHJpbnQocGFzdGUoIk1BUEUgPSAiLCBNQVBFKHByZWRpY3RlZF9tZWFuc19iZXN0X3BhcmFtJHByZWRpY3RlZF9wZXJjLCBhY3R1YWxfbWl4XzIwMThfcmVkdWNlZCR2YWx1ZV9wZXJjKSkpCgpgYGAKCmBgYHtyfQpwID0gYmVzdF9wYXJhbXMgJT4lIHRyYW5zZm9ybSh5PWdldF9saW5lKGluZGl2aWR1YWxfYywgaW5kaXZpZHVhbF9tKSwgeD1nZXRfeCgpKSAgJT4lIGdncGxvdCgpICsgZ2VvbV9saW5lKGFlcyh4PXguMSwgeT14KSkrIHN0YXRfc21vb3RoKGRhdGE9cGRjX2V4YW1wbGUsIGFlcyh4PXNlZ21lbnRfZGVtYW5kLCB5PWFjY2VwdGVkX3ByaWNlKSwgbWV0aG9kPSJsbSIsIGNvbD0ieWVsbG93IikgKyBnZW9tX3BvaW50KGRhdGE9cGRjX2V4YW1wbGUsIGFlcyh4PXNlZ21lbnRfZGVtYW5kLCB5PWFjY2VwdGVkX3ByaWNlKSkgKyB4bGFiKCJEZW1hbmQgKE1XKSIpICsgeWxhYigiQWNjZXB0ZWQgUHJpY2UiKSArIGdndGl0bGUoIkJlc3QgcGFyYW1hdGVyIGNvbWJpbmF0aW9uIHByaWNlIGN1cnZlIikKcCRsYWJlbHMkZmlsbCA8LSAiUGVyY2VudGlsZXMiCnByaW50KHApCgpgYGAKCgojIENhbGN1bGF0aW9uIG9mIGJlc3QgcGFyYW1ldGVycyB3aXRoIGxvd2VzdCB2YXJpYW5jZSBhbmQgZXJyb3IKYGBge3J9CiMgYmVzdF9wYXJhbXMgPSBwYXJhbXNfbW9yZV90aGFuXzEwICU+JSBncm91cF9ieShpbmRpdmlkdWFsX2MsIGluZGl2aWR1YWxfbSkgJT4lIGdhdGhlcigia2V5IiwgInZhbHVlIiwgImNvYWwiLCAiY2NndCIsICJ3aW5kIiwgIm51Y2xlYXIiLCAic29sYXIiKSAlPiUgZ3JvdXBfYnkoaWQpICU+JSBtdXRhdGUodmFsdWVfcGVyYyA9IHZhbHVlL3N1bSh2YWx1ZSkpICU+JSBncm91cF9ieShpZCwga2V5KSAlPiUgaW5uZXJfam9pbihhY3R1YWxfbWl4XzIwMThfcmVkdWNlZCwgYnk9ImtleSIpICU+JSBtdXRhdGUoZGlmZl9wZXJjID0gYWJzKHZhbHVlX3BlcmMueC12YWx1ZV9wZXJjLnkpKSAlPiUgZ3JvdXBfYnkoaWQpICU+JSBzdW1tYXJpc2UobWVhbl9kaWZmX3BlcmMgPSBtZWFuKGRpZmZfcGVyYyksIGluZGl2aWR1YWxfYyA9IG1lYW4oaW5kaXZpZHVhbF9jKSwgaW5kaXZpZHVhbF9tID0gbWVhbihpbmRpdmlkdWFsX20pKSAlPiUgZmlsdGVyKHJhbmsobWVhbl9kaWZmX3BlcmMsIHRpZXMubWV0aG9kPSJmaXJzdCIpPT0xKQoKIyBjYWxjdWxhdGVfbWVhbl9lcnJvciA9IGZ1bmN0aW9uKGRmKXsKIyAgICAgCiMgICAgIHJldHVybihnYXRoZXIoZGYsICJrZXkiLCAidmFsdWUiLCAiY29hbCIsICJjY2d0IiwgIndpbmQiLCAibnVjbGVhciIsICJzb2xhciIpICU+JSBpbm5lcl9qb2luKGFjdHVhbF9taXhfMjAxOF9yZWR1Y2VkLCBieT0na2V5JykpCiMgfQoKIyBwYXJhbXNfbW9yZV90aGFuXzEwICU+JSBncm91cF9ieShpbmRpdmlkdWFsX2MsIGluZGl2aWR1YWxfbSkgJT4lIGRvKC4sIGNhbGN1bGF0ZV9tZWFuX2Vycm9yKQojIGRkcGx5KHBhcmFtc19tb3JlX3RoYW5fMTAsIC4oaW5kaXZpZHVhbF9jLCBpbmRpdmlkdWFsX20pLCBjYWxjdWxhdGVfbWVhbl9lcnJvcikKCnBhcmFtc19zZF9tZWFuX3Jld2FyZCA9IHBhcmFtc19tb3JlX3RoYW5fMTAgJT4lIGRwbHlyOjpncm91cF9ieShpbmRpdmlkdWFsX2MsIGluZGl2aWR1YWxfbSkgJT4lIGdhdGhlcigia2V5IiwgInZhbHVlIiwgImNvYWwiLCAiY2NndCIsICJ3aW5kIiwgIm51Y2xlYXIiLCAic29sYXIiKSAlPiUgZHBseXI6Omdyb3VwX2J5KGlkKSAlPiUgZHBseXI6Om11dGF0ZSh2YWx1ZV9wZXJjID0gdmFsdWUvc3VtKHZhbHVlKSkgJT4lIGRwbHlyOjpncm91cF9ieShpZCwga2V5KSAlPiUgZHBseXI6OmlubmVyX2pvaW4oYWN0dWFsX21peF8yMDE4X3JlZHVjZWQsIGJ5PSJrZXkiKSAlPiUgZHBseXI6Om11dGF0ZShkaWZmX3BlcmMgPSBhYnModmFsdWVfcGVyYy54LXZhbHVlX3BlcmMueSkpICU+JSBkcGx5cjo6Z3JvdXBfYnkoaWQpICU+JSBkcGx5cjo6c3VtbWFyaXNlKGRpZmZfc2QgPSBzZChkaWZmX3BlcmMpLCBtZWFuX2RpZmZfcGVyYyA9IG1lYW4oZGlmZl9wZXJjKSwgaW5kaXZpZHVhbF9jID0gbWVhbihpbmRpdmlkdWFsX2MpLCBpbmRpdmlkdWFsX20gPSBtZWFuKGluZGl2aWR1YWxfbSkpICU+JSBkcGx5cjo6Z3JvdXBfYnkoaW5kaXZpZHVhbF9jLCBpbmRpdmlkdWFsX20pICU+JSBkcGx5cjo6c3VtbWFyaXNlKGRpZmZfc2QgPSBzZChkaWZmX3NkKSwgbWVhbl9kaWZmX3BlcmMgPSBkcGx5cjo6bWVhbihtZWFuX2RpZmZfcGVyYykpCgpwYXJhbXNfc2RfbWVhbl9yZXdhcmRfb3JkZXJlZCA9IGFycmFuZ2UocGFyYW1zX3NkX21lYW5fcmV3YXJkLCBkaWZmX3NkLCBtZWFuX2RpZmZfcGVyYykKZnJvbnRpZXIgPSBnZXRfZnJvbnRpZXIoYXMuZGF0YS5mcmFtZShwYXJhbXNfc2RfbWVhbl9yZXdhcmRfb3JkZXJlZCksIGRpZmZfc2QsIG1lYW5fZGlmZl9wZXJjLCBkZWNyZWFzaW5nID0gRkFMU0UsIHF1YWRyYW50ID0gImJvdHRvbS5sZWZ0IikKCnBhcmFtc19zZF9tZWFuX3Jld2FyZCAlPiUgZ2dwbG90KCkgKyBnZW9tX3BvaW50KGFlcyhkaWZmX3NkLCBtZWFuX2RpZmZfcGVyYykpICsgZ2VvbV9saW5lKGRhdGE9ZnJvbnRpZXIsIGFlcyhkaWZmX3NkLCBtZWFuX2RpZmZfcGVyYyksIGNvbG9yPSJyZWQiKSArIGdndGl0bGUoIlBhcmV0byBmcm9udGllciBvZiBzdGFuZGFyZCBkZXZpYXRpb24gdmVyc3VzIG1lYW4gZm9yIHNpbXVsYXRpb25zIFxub2YgbW9yZSB0aGFuIDEwIHJ1bnMiKQoKYGBgCgpgYGB7cn0KcGFyYW1zX21vcmVfdGhhbl8xMF9wZXJjID0gcGFyYW1zX21vcmVfdGhhbl8xMCAlPiUgZHBseXI6Omdyb3VwX2J5KGluZGl2aWR1YWxfYywgaW5kaXZpZHVhbF9tKSAlPiUgZ2F0aGVyKCJrZXkiLCAidmFsdWUiLCAiY29hbCIsICJjY2d0IiwgIndpbmQiLCAibnVjbGVhciIsICJzb2xhciIpICU+JSBncm91cF9ieShpZCkgJT4lIGRwbHlyOjptdXRhdGUodmFsdWVfcGVyYyA9IHZhbHVlL3N1bSh2YWx1ZSkpCgpmcm9udGllcl9mdWxsX2RhdGEgPSBmcm9udGllciAlPiUgZHBseXI6OmlubmVyX2pvaW4ocGFyYW1zX3NkX21lYW5fcmV3YXJkX29yZGVyZWQsIGJ5PWMoJ2RpZmZfc2QnLCAnbWVhbl9kaWZmX3BlcmMnKSkgJT4lZHBseXI6OiBpbm5lcl9qb2luKHBhcmFtc19tb3JlX3RoYW5fMTBfcGVyYywgYnk9YygiaW5kaXZpZHVhbF9jIiwgImluZGl2aWR1YWxfbSIpKSAlPiUgZHBseXI6Om11dGF0ZSh0eXBlPXBhc3RlKG1lYW5fZGlmZl9wZXJjLGRpZmZfc2QpKQoKCnJiaW5kKGZpbHRlcihzZWxlY3QoZnJvbnRpZXJfZnVsbF9kYXRhLCAia2V5IiwgInR5cGUiLCAidmFsdWUiLCAndmFsdWVfcGVyYycpKSwgc2VsZWN0KGFjdHVhbF9taXhfMjAxOF9yZWR1Y2VkLCAtWDEsIC15ZWFyKSkgJT4lIGdncGxvdChhZXMoeD1rZXksIHk9dmFsdWVfcGVyYywgZmlsbD10eXBlKSkgKyBzdGF0X3N1bW1hcnkoZ2VvbSA9ICJiYXIiLCBmdW4ueSA9IG1lYW4sIHBvc2l0aW9uID0gImRvZGdlMiIpKyBzdGF0X3N1bW1hcnkoZ2VvbSA9ICJlcnJvcmJhciIsIGZ1bi5kYXRhID0gbWVhbl9zZSwgcG9zaXRpb24gPSAiZG9kZ2UyIikgKyBnZ3RpdGxlKCJCZXN0IHBhcmFtZXRlciBjb21iaW5hdGlvbnMgZnJvbSBhbGwgZ2VuZXRpYyBhbGdvcml0aG0gcnVucyIpCiAgICAKYGBgCgpgYGB7cn0KYmVzdF9vbmUgPSBkcGx5cjo6c2VsZWN0KGRwbHlyOjpmaWx0ZXIoZnJvbnRpZXJfZnVsbF9kYXRhLCBtZWFuX2RpZmZfcGVyYzwwLjA2NyksICJrZXkiLCAidHlwZSIsICJ2YWx1ZSIsICd2YWx1ZV9wZXJjJykKYmVzdF9vbmUkdHlwZSA9ICJTaW11bGF0ZWQiCgphY3R1YWxfbWl4XzIwMThfcmVkdWNlZCR0eXBlID0gIkFjdHVhbCIKCnJiaW5kKGJlc3Rfb25lLCBzZWxlY3QoYWN0dWFsX21peF8yMDE4X3JlZHVjZWQsIC1YMSwgLXllYXIpKSAlPiUgZ2dwbG90KGFlcyh4PWtleSwgeT12YWx1ZV9wZXJjLCBmaWxsPXR5cGUpKSArIHN0YXRfc3VtbWFyeShnZW9tID0gImJhciIsIGZ1bi55ID0gbWVhbiwgcG9zaXRpb24gPSAiZG9kZ2UyIikrIHN0YXRfc3VtbWFyeShnZW9tID0gImVycm9yYmFyIiwgZnVuLmRhdGEgPSBtZWFuX3NlLCBwb3NpdGlvbiA9ICJkb2RnZTIiKSArIHRoZW1lX2NsYXNzaWMoKSArdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE4KSkrIHhsYWIoIiIpICsgeWxhYigiRWxlY3RyaWNpdHkgTWl4ICglKSIpICtzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gJ1NldDInKQoKZ2dzYXZlKCJ+L0RvY3VtZW50cy9QaEQvUHJvamVjdHMvMTAtRUxFQ1NJTS9ub3RlYm9va3MvdmFsaWRhdGlvbi1vcHRpbWlzYXRpb24vZmlndXJlcy9pbnRyb2R1Y3Rpb24vYmVzdF9ydW4ucGRmIikKYGBgCgpgYGB7cn0KYmVzdF9hY3R1YWwgPSByYmluZChiZXN0X29uZSwgc2VsZWN0KGFjdHVhbF9taXhfMjAxOF9yZWR1Y2VkLCAtWDEsIC15ZWFyKSkKYmVzdF9hY3R1YWxfc3RhdHMgPSBiZXN0X2FjdHVhbCAlPiUgZHBseXI6Omdyb3VwX2J5KHR5cGUsIGtleSkgJT4lIGRwbHlyOjpzdW1tYXJpc2Uoc2RfdmFsdWUgPSBzZCh2YWx1ZV9wZXJjKSwgbWVhbl92YWx1ZSA9IG1lYW4odmFsdWVfcGVyYykpIAoKYWN0dWFscyA9IGRwbHlyOjpmaWx0ZXIoYmVzdF9hY3R1YWxfc3RhdHMsIHR5cGU9PSJBY3R1YWwiKSRtZWFuX3ZhbHVlCnByZWRpY3RlZCA9IGRwbHlyOjpmaWx0ZXIoYmVzdF9hY3R1YWxfc3RhdHMsIHR5cGU9PSJTaW11bGF0ZWQiKSRtZWFuX3ZhbHVlCgpSTVNFKGFjdHVhbHMscHJlZGljdGVkKQpgYGAKCmBgYHtyfQpiZXN0X2MgPSBmaWx0ZXIoZnJvbnRpZXJfZnVsbF9kYXRhLCBtZWFuX2RpZmZfcGVyYzwwLjA2NykkaW5kaXZpZHVhbF9jWzFdCmJlc3RfbSA9IGZpbHRlcihmcm9udGllcl9mdWxsX2RhdGEsIG1lYW5fZGlmZl9wZXJjPDAuMDY3KSRpbmRpdmlkdWFsX21bMV0KCmJlc3RfcGFyYW1zICU+JSB0cmFuc2Zvcm0oeT1nZXRfbGluZShiZXN0X2MsIGJlc3RfbSksIHg9Z2V0X3goKSkgICU+JSBnZ3Bsb3QoKSArIHN0YXRfc21vb3RoKGRhdGE9cGRjX2V4YW1wbGUsIGFlcyh4PXNlZ21lbnRfZGVtYW5kLCB5PWFjY2VwdGVkX3ByaWNlLCBjb2xvcj0iU2ltdWxhdGVkIEZpdCAoMjAxOCkiKSwgbWV0aG9kPSJsbSIpICsgZ2VvbV9wb2ludChkYXRhPXBkY19leGFtcGxlLCBhZXMoeD1zZWdtZW50X2RlbWFuZCwgeT1hY2NlcHRlZF9wcmljZSwgY29sb3I9IlBEQyAoMjAxOCkiKSkgKyBnZW9tX2xpbmUoYWVzKHg9eC4xLCB5PXgsIGNvbG9yPSJQUERDIiksIHNpemU9MikgKyB4bGFiKCJEZW1hbmQgKE1XKSIpICsgeWxhYigiQWNjZXB0ZWQgUHJpY2UgKMKjL01XaCkiKSArIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gIkRhdGEiLCAgdmFsdWVzID0gYygiUERDICgyMDE4KSIgPSAib3JhbmdlIiwgIlBQREMiID0gIiMzMDY5OTYiLCAnU2ltdWxhdGVkIEZpdCAoMjAxOCknPSdyZWQnKSkgICsgdGhlbWVfY2xhc3NpYygpICt0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTgpKSsgdGhlbWUoYXNwZWN0LnJhdGlvID0gMSwgcGxvdC5tYXJnaW49Z3JpZDo6dW5pdChjKDAsMCwwLDApLCAibW0iKSkgCgoKZ2dzYXZlKCJ+L0RvY3VtZW50cy9QaEQvUHJvamVjdHMvMTAtRUxFQ1NJTS9ub3RlYm9va3MvdmFsaWRhdGlvbi1vcHRpbWlzYXRpb24vZmlndXJlcy9yZXN1bHRzL2Jlc3RfcnVuX3ByaWNlX2R1cl9jdXJ2ZS5wZGYiLCBkcGk9MTAwMCkKYGBgCgpgYGB7cn0KcD1nZ3Bsb3QocnVuXzEsIGFlcyh5PWluZGl2aWR1YWxfbSwgeD1pbmRpdmlkdWFsX2MpKSArIHN0YXRfc3VtbWFyeV9oZXgoYWVzKHogPSB0aW1lX3Rha2VuKSwgYmlucz0xMCkgKyBmYWNldF93cmFwKH4gcnVuX251bWJlcikgKyBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gcm91bmQoc2VxKG1pbihydW5fMSRpbmRpdmlkdWFsX2MpLCBtYXgocnVuXzEkaW5kaXZpZHVhbF9jKSwgYnkgPSAyNSksMSkpICsgZ2d0aXRsZSgiSGV4YWdvbmFsIGhlYXRtYXAgb2YgaW5wdXQgcGFyYW1ldGVycyBhZ2FpbnN0IHRpbWUgdGFrZW4gd2l0aCByZXNwZWN0IHRvIHBvcHVsYXRpb24gbnVtYmVyIikKcCRsYWJlbHMkZmlsbCA8LSAiVGltZSBcbiBUYWtlbiIKcHJpbnQocCkKCmdnc2F2ZSgnfi9EZXNrdG9wL3RpbWUtdGFrZW4tcGFyYW1ldGVycy5wbmcnKQpgYGAKCmBgYHtyfQpydW5fMSAlPiUgYXJyYW5nZShkZXNjKHJ1bl9udW1iZXIpKSAlPiUgZ2dwbG90KGFscGhhPTAuMSwgYWVzKHk9aW5kaXZpZHVhbF9tLCB4PWluZGl2aWR1YWxfYykpICsgZ2VvbV9wb2ludChhZXMoY29sb3I9cnVuX251bWJlciwgc2l6ZT10aW1lX3Rha2VuKSkgKyBnZ3RpdGxlKCJTY2F0dGVyIHBsb3Qgc2hvd2luZyBydW4gbnVtYmVyIGFnYWluc3QgdGltZSB0YWtlbiBhbmQgcmV3YXJkIikKYGBgCgpgYGB7cn0KcnVuXzEgJT4lIGZpbHRlcihpbmRpdmlkdWFsX2M8LTMsIGluZGl2aWR1YWxfbSA8MC4wMDI1LCBpbmRpdmlkdWFsX20gPiAwLjAwMTUpICU+JSBnZ3Bsb3QoYWVzKHg9YXMuZmFjdG9yKHJ1bl9udW1iZXIpLCB5PXRpbWVfdGFrZW4pKSArIGdlb21fdmlvbGluKCkgKyBnZ3RpdGxlKCJWaW9saW4gcGxvdCBvZiB0aW1lIHRha2VuIGZvciBlYWNoIHNpbXVsYXRpb24gcnVuIGFnYWluc3QgcG9wdWxhdGlvbiBudW1iZXIiKQpgYGAKYGBge3J9CmdncGxvdChkYXRhPXJ1bl8xLCBhZXMoeD1hcy5mYWN0b3IocnVuX251bWJlciksIHk9cmV3YXJkKSkrZ2VvbV9ib3hwbG90KCkrZ2VvbV9qaXR0ZXIocG9zaXRpb249cG9zaXRpb25faml0dGVyKDAuMiksIGFscGhhPTAuNSwgY29sb3I9J2JsdWUnKSArIGdndGl0bGUoIkJveHBsb3QgYW5kIGppdHRlciBvZiBydW4gbnVtYmVyIGFnYWluc3QgcmV3YXJkIikKYGBgCgoKYGBge3J9CnJ1bl8xICU+JSBmaWx0ZXIoaW5kaXZpZHVhbF9jPC0zLCBpbmRpdmlkdWFsX20gPDAuMDAyNSwgaW5kaXZpZHVhbF9tID4gMC4wMDE1KSAlPiUgZ2dwbG90KGFlcyh4PWFzLmZhY3RvcihydW5fbnVtYmVyKSwgeT1yZXdhcmQpKSArIGdlb21fdmlvbGluKCkgKyBnZ3RpdGxlKCJWaW9saW4gcGxvdCBvZiByZXdhcmQgYWdhaW5zdCBwb3B1bGF0aW9uIG51bWJlciIpCgpgYGAKCmBgYHtyfQpnZ3Bsb3QocnVuXzEsIGFlcyh4PXJld2FyZCwgeT10aW1lX3Rha2VuKSkrc3RhdF9zbW9vdGgobWV0aG9kID0gImxtIikrZ2VvbV9wb2ludCgpK3hsYWIoIkFic29sdXRlIFBlcmNlbnRhZ2UgRXJyb3IiKSArIGdndGl0bGUoIlNjYXR0ZXIgcGxvdCBvZiB0aW1lIHRha2VuIGZvciBlYWNoIHNpbXVsYXRpb24gcnVuIGFnYWluc3QgXG5hYnNvbHV0ZSBwZXJjZW50YWdlIGVycm9yIikKCmBgYAoKYGBge3J9CmRpZl9zdW0gPSBydW5fMV9sb25nICU+JSBpbm5lcl9qb2luKGFjdHVhbF9taXhfMjAxOF9yZWR1Y2VkLCBieT0na2V5JykgJT4lIGdyb3VwX2J5KGlkLGtleSkgJT4lIG11dGF0ZSh0b3RhbF9kaWZmZXJlbmNlID0gdmFsdWUueC12YWx1ZS55KSAlPiUgZGRwbHkoLihpZCwga2V5KSwgc3VtbWFyaXNlLCBkaWZmZXJlbmNlX3N1bSA9IHN1bSh0b3RhbF9kaWZmZXJlbmNlKSwgdGltZV90YWtlbj10aW1lX3Rha2VuLCByZXdhcmQ9cmV3YXJkLCBydW5fbnVtYmVyPXJ1bl9udW1iZXIpICU+JSBncm91cF9ieShpZCkgJT4lIHN1bW1hcmlzZSh0b3RfZGlmZiA9IHN1bShkaWZmZXJlbmNlX3N1bSksIHRpbWVfdGFrZW49bWVhbih0aW1lX3Rha2VuKSwgcmV3YXJkPW1lYW4ocmV3YXJkKSwgcnVuX251bWJlcj1tZWFuKHJ1bl9udW1iZXIpKQoKcGxvdF9seShkYXRhPWRpZl9zdW0sIHg9fnRvdF9kaWZmLCB5PX50aW1lX3Rha2VuLCB6PX5yZXdhcmQsIHR5cGU9InNjYXR0ZXIzZCIsIG1vZGU9Im1hcmtlcnMiLCBjb2xvcj1+cnVuX251bWJlcikgCmBgYAoKYGBge3J9CmdncGxvdCgpK2dlb21fcG9pbnQoZGF0YT1ydW5fMSwgYWVzKHg9dGltZV90YWtlbiwgeT1yZXdhcmQsIGNvbG9yPXJ1bl9udW1iZXIpKSArIGdndGl0bGUoIlNjYXR0ZXIgcGxvdCBvZiB0aW1lIHRha2VuIGFnYWluc3QgcmV3YXJkIikKYGBgCgpgYGB7cn0KcnVuXzEKCnJ1bl8xX2xvbmcgPSBnYXRoZXIocnVuXzEsICJrZXkiLCAidmFsdWUiLCAiY29hbCIsICJjY2d0IiwgIndpbmQiLCAibnVjbGVhciIsICJzb2xhciIpCgojIHJ1bl8xX2xvbmcgJT4lIGlubmVyX2pvaW4oYWN0dWFsX21peF8yMDE4X3JlZHVjZWQsIGJ5PSdrZXknKSAlPiUgZ3JvdXBfYnkoaWQsa2V5KSAlPiUgbXV0YXRlKHRvdGFsX2RpZmZlcmVuY2UgPSB2YWx1ZS54LXZhbHVlLnkpICU+JSBncm91cF9ieShpZCwga2V5KSAlPiUgc3VtbWFyaXNlKGRpZmZlcmVuY2Vfc3VtID0gc3VtKHRvdGFsX2RpZmZlcmVuY2UpKQoKZ2dwbG90KGRhdGE9ZGlmX3N1bSwgYWVzKHg9dG90X2RpZmYsIHk9dGltZV90YWtlbiwgY29sb3I9cmV3YXJkKSkgKyBnZW9tX3BvaW50KCkrZ2VvbV9zbW9vdGgoKSt4bGltKC0xMTAwMCwxMDAwMCkKCiMgYWN0dWFsX21peF8yMDE4X3JlZHVjZWQKYGBgCmBgYHtyfQpnZ3Bsb3QoZGF0YT1kaWZfc3VtLCBhZXMoeD10b3RfZGlmZiwgY29sb3I9dGltZV90YWtlbiwgeT1yZXdhcmQpKSArIGdlb21fcG9pbnQoKStnZW9tX3Ntb290aCgpK3hsaW0oLTExMDAwLDEwMDAwKQpgYGAKCmBgYHtyfQpnZ3Bsb3QocnVuXzEsIGFlcyh4PXJ1bl9udW1iZXIsIHk9dGltZV90YWtlbiwgY29sb3I9cmV3YXJkKSkgKyBnZW9tX3BvaW50KCkgKwogICBnZW9tX3Ntb290aChtZXRob2Q9J2xtJykKYGBg
>>>>>>> 7a2bca4ba0351e30ac6a91f57db3c5decf93d8fb